ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
esp_color_correction.h
Go to the documentation of this file.
1#pragma once
2
5#include "esphome/core/hal.h"
6
7#include <algorithm>
8
9namespace esphome::light {
10
12struct GammaTable {
13 uint16_t lut[256];
14 uint16_t gamma_x100;
15};
16
19inline uint8_t gamma_table_reverse_search(const uint16_t *table, uint16_t target) {
20 uint8_t lo = 0, hi = 255;
21 while (lo < hi) {
22 uint8_t mid = (lo + hi + 1) / 2;
23 if (progmem_read_uint16(&table[mid]) <= target) {
24 lo = mid;
25 } else {
26 hi = mid - 1;
27 }
28 }
29 return lo;
30}
31
33 public:
34 void set_max_brightness(const Color &max_brightness) { this->max_brightness_ = max_brightness; }
35 void set_local_brightness(uint8_t local_brightness) { this->local_brightness_ = local_brightness; }
36#ifdef USE_LIGHT_POWER_ESTIMATION
37 // The current limit's factor, applied after gamma
38 void set_power_brightness(uint8_t power_brightness) { this->power_brightness_ = power_brightness; }
39 uint8_t get_power_brightness() const { return this->power_brightness_; }
40#endif
41 void set_gamma_table(const uint16_t *table) { this->gamma_table_ = table; }
42 inline Color color_correct(Color color) const ESPHOME_ALWAYS_INLINE {
43 // corrected = (uncorrected * max_brightness * local_brightness) ^ gamma
44 return Color(this->color_correct_red(color.red), this->color_correct_green(color.green),
45 this->color_correct_blue(color.blue), this->color_correct_white(color.white));
46 }
47 inline uint8_t color_correct_red(uint8_t red) const ESPHOME_ALWAYS_INLINE {
48 return this->color_correct_channel_(red, this->max_brightness_.red);
49 }
50 inline uint8_t color_correct_green(uint8_t green) const ESPHOME_ALWAYS_INLINE {
51 return this->color_correct_channel_(green, this->max_brightness_.green);
52 }
53 inline uint8_t color_correct_blue(uint8_t blue) const ESPHOME_ALWAYS_INLINE {
54 return this->color_correct_channel_(blue, this->max_brightness_.blue);
55 }
56 inline uint8_t color_correct_white(uint8_t white) const ESPHOME_ALWAYS_INLINE {
57 return this->color_correct_channel_(white, this->max_brightness_.white);
58 }
59 Color color_uncorrect(Color color) const;
60 inline uint8_t color_uncorrect_red(uint8_t red) const ESPHOME_ALWAYS_INLINE {
61 return this->color_uncorrect_channel_(red, this->max_brightness_.red);
62 }
63 inline uint8_t color_uncorrect_green(uint8_t green) const ESPHOME_ALWAYS_INLINE {
64 return this->color_uncorrect_channel_(green, this->max_brightness_.green);
65 }
66 inline uint8_t color_uncorrect_blue(uint8_t blue) const ESPHOME_ALWAYS_INLINE {
67 return this->color_uncorrect_channel_(blue, this->max_brightness_.blue);
68 }
69 inline uint8_t color_uncorrect_white(uint8_t white) const ESPHOME_ALWAYS_INLINE {
70 return this->color_uncorrect_channel_(white, this->max_brightness_.white);
71 }
72
73 protected:
74 inline uint8_t color_correct_channel_(uint8_t value, uint8_t max_brightness) const ESPHOME_ALWAYS_INLINE {
75 return this->limit_(this->gamma_correct_(esp_scale8_twice(value, max_brightness, this->local_brightness_)));
76 }
77 // The limit on a gamma-corrected level; rounded up, so a lit channel stays lit
78 inline uint8_t limit_(uint8_t res) const ESPHOME_ALWAYS_INLINE {
79#ifdef USE_LIGHT_POWER_ESTIMATION
80 if (res != 0)
81 res = std::max<uint8_t>(esp_scale8(res, this->power_brightness_), 1);
82#endif
83 return res;
84 }
86 uint8_t gamma_correct_(uint8_t value) const;
88 uint8_t uncorrect_level_(uint8_t value) const;
90 uint8_t gamma_uncorrect_(uint8_t value) const;
93 uint8_t color_uncorrect_channel_(uint8_t value, uint8_t max_brightness) const;
94
95 const uint16_t *gamma_table_{nullptr};
96 Color max_brightness_{255, 255, 255, 255};
97 uint8_t local_brightness_{255};
98#ifdef USE_LIGHT_POWER_ESTIMATION
99 uint8_t power_brightness_{255};
100#endif
101};
102
103} // namespace esphome::light
uint8_t gamma_correct_(uint8_t value) const
Forward gamma: read uint16 PROGMEM table, convert to uint8.
void set_power_brightness(uint8_t power_brightness)
uint8_t color_correct_channel_(uint8_t value, uint8_t max_brightness) const ESPHOME_ALWAYS_INLINE
uint8_t color_uncorrect_red(uint8_t red) const ESPHOME_ALWAYS_INLINE
uint8_t color_correct_blue(uint8_t blue) const ESPHOME_ALWAYS_INLINE
void set_max_brightness(const Color &max_brightness)
uint8_t color_correct_red(uint8_t red) const ESPHOME_ALWAYS_INLINE
uint8_t color_uncorrect_channel_(uint8_t value, uint8_t max_brightness) const
Shared body of color_uncorrect_{red,green,blue,white}.
void set_local_brightness(uint8_t local_brightness)
Color color_correct(Color color) const ESPHOME_ALWAYS_INLINE
uint8_t color_uncorrect_blue(uint8_t blue) const ESPHOME_ALWAYS_INLINE
void set_gamma_table(const uint16_t *table)
uint8_t color_uncorrect_green(uint8_t green) const ESPHOME_ALWAYS_INLINE
uint8_t uncorrect_level_(uint8_t value) const
Reverse gamma and limit for one stored level.
uint8_t color_correct_green(uint8_t green) const ESPHOME_ALWAYS_INLINE
uint8_t limit_(uint8_t res) const ESPHOME_ALWAYS_INLINE
uint8_t gamma_uncorrect_(uint8_t value) const
Reverse gamma: binary search the forward PROGMEM table.
uint8_t color_correct_white(uint8_t white) const ESPHOME_ALWAYS_INLINE
uint8_t color_uncorrect_white(uint8_t white) const ESPHOME_ALWAYS_INLINE
uint8_t gamma_table_reverse_search(const uint16_t *table, uint16_t target)
Binary search a monotonically increasing uint16[256] PROGMEM table.
uint16_t progmem_read_uint16(const uint16_t *addr)
Definition hal.h:53
uint8_t red
Definition color.h:31
uint8_t white
Definition color.h:43
uint8_t green
Definition color.h:35
uint8_t blue
Definition color.h:39
A gamma curve as codegen emits it into PROGMEM: the lookup table and the gamma it was built from.