ESPHome  2025.2.0
image.cpp
Go to the documentation of this file.
1 #include "image.h"
2 
3 #include "esphome/core/hal.h"
4 
5 namespace esphome {
6 namespace image {
7 
8 void Image::draw(int x, int y, display::Display *display, Color color_on, Color color_off) {
9  switch (type_) {
10  case IMAGE_TYPE_BINARY: {
11  for (int img_x = 0; img_x < width_; img_x++) {
12  for (int img_y = 0; img_y < height_; img_y++) {
13  if (this->get_binary_pixel_(img_x, img_y)) {
14  display->draw_pixel_at(x + img_x, y + img_y, color_on);
15  } else if (!this->transparency_) {
16  display->draw_pixel_at(x + img_x, y + img_y, color_off);
17  }
18  }
19  }
20  break;
21  }
23  for (int img_x = 0; img_x < width_; img_x++) {
24  for (int img_y = 0; img_y < height_; img_y++) {
25  const uint32_t pos = (img_x + img_y * this->width_);
26  const uint8_t gray = progmem_read_byte(this->data_start_ + pos);
27  Color color = Color(gray, gray, gray, 0xFF);
28  switch (this->transparency_) {
30  if (gray == 1) {
31  continue; // skip drawing
32  }
33  break;
35  auto on = (float) gray / 255.0f;
36  auto off = 1.0f - on;
37  // blend color_on and color_off
38  color = Color(color_on.r * on + color_off.r * off, color_on.g * on + color_off.g * off,
39  color_on.b * on + color_off.b * off, 0xFF);
40  break;
41  }
42  default:
43  break;
44  }
45  display->draw_pixel_at(x + img_x, y + img_y, color);
46  }
47  }
48  break;
49  case IMAGE_TYPE_RGB565:
50  for (int img_x = 0; img_x < width_; img_x++) {
51  for (int img_y = 0; img_y < height_; img_y++) {
52  auto color = this->get_rgb565_pixel_(img_x, img_y);
53  if (color.w >= 0x80) {
54  display->draw_pixel_at(x + img_x, y + img_y, color);
55  }
56  }
57  }
58  break;
59  case IMAGE_TYPE_RGB:
60  for (int img_x = 0; img_x < width_; img_x++) {
61  for (int img_y = 0; img_y < height_; img_y++) {
62  auto color = this->get_rgb_pixel_(img_x, img_y);
63  if (color.w >= 0x80) {
64  display->draw_pixel_at(x + img_x, y + img_y, color);
65  }
66  }
67  }
68  break;
69  }
70 }
71 Color Image::get_pixel(int x, int y, const Color color_on, const Color color_off) const {
72  if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
73  return color_off;
74  switch (this->type_) {
75  case IMAGE_TYPE_BINARY:
76  if (this->get_binary_pixel_(x, y))
77  return color_on;
78  return color_off;
80  return this->get_grayscale_pixel_(x, y);
81  case IMAGE_TYPE_RGB565:
82  return this->get_rgb565_pixel_(x, y);
83  case IMAGE_TYPE_RGB:
84  return this->get_rgb_pixel_(x, y);
85  default:
86  return color_off;
87  }
88 }
89 #ifdef USE_LVGL
90 lv_img_dsc_t *Image::get_lv_img_dsc() {
91  // lazily construct lvgl image_dsc.
92  if (this->dsc_.data != this->data_start_) {
93  this->dsc_.data = this->data_start_;
94  this->dsc_.header.always_zero = 0;
95  this->dsc_.header.reserved = 0;
96  this->dsc_.header.w = this->width_;
97  this->dsc_.header.h = this->height_;
98  this->dsc_.data_size = this->get_width_stride() * this->get_height();
99  switch (this->get_type()) {
100  case IMAGE_TYPE_BINARY:
101  this->dsc_.header.cf = LV_IMG_CF_ALPHA_1BIT;
102  break;
103 
105  this->dsc_.header.cf = LV_IMG_CF_ALPHA_8BIT;
106  break;
107 
108  case IMAGE_TYPE_RGB:
109 #if LV_COLOR_DEPTH == 32
110  switch (this->transparent_) {
112  this->dsc_.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA;
113  break;
115  this->dsc_.header.cf = LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED;
116  break;
117  default:
118  this->dsc_.header.cf = LV_IMG_CF_TRUE_COLOR;
119  break;
120  }
121 #else
122  this->dsc_.header.cf =
123  this->transparency_ == TRANSPARENCY_ALPHA_CHANNEL ? LV_IMG_CF_RGBA8888 : LV_IMG_CF_RGB888;
124 #endif
125  break;
126 
127  case IMAGE_TYPE_RGB565:
128 #if LV_COLOR_DEPTH == 16
129  switch (this->transparency_) {
131  this->dsc_.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA;
132  break;
134  this->dsc_.header.cf = LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED;
135  break;
136  default:
137  this->dsc_.header.cf = LV_IMG_CF_TRUE_COLOR;
138  break;
139  }
140 #else
141  this->dsc_.header.cf = this->transparent_ == TRANSPARENCY_ALPHA_CHANNEL ? LV_IMG_CF_RGB565A8 : LV_IMG_CF_RGB565;
142 #endif
143  break;
144  }
145  }
146  return &this->dsc_;
147 }
148 #endif // USE_LVGL
149 
150 bool Image::get_binary_pixel_(int x, int y) const {
151  const uint32_t width_8 = ((this->width_ + 7u) / 8u) * 8u;
152  const uint32_t pos = x + y * width_8;
153  return progmem_read_byte(this->data_start_ + (pos / 8u)) & (0x80 >> (pos % 8u));
154 }
155 Color Image::get_rgb_pixel_(int x, int y) const {
156  const uint32_t pos = (x + y * this->width_) * this->bpp_ / 8;
157  Color color = Color(progmem_read_byte(this->data_start_ + pos + 0), progmem_read_byte(this->data_start_ + pos + 1),
158  progmem_read_byte(this->data_start_ + pos + 2), 0xFF);
159 
160  switch (this->transparency_) {
162  if (color.g == 1 && color.r == 0 && color.b == 0) {
163  // (0, 1, 0) has been defined as transparent color for non-alpha images.
164  color.w = 0;
165  }
166  break;
168  color.w = progmem_read_byte(this->data_start_ + (pos + 3));
169  break;
170  default:
171  break;
172  }
173  return color;
174 }
176  const uint8_t *pos = this->data_start_ + (x + y * this->width_) * this->bpp_ / 8;
177  uint16_t rgb565 = encode_uint16(progmem_read_byte(pos), progmem_read_byte(pos + 1));
178  auto r = (rgb565 & 0xF800) >> 11;
179  auto g = (rgb565 & 0x07E0) >> 5;
180  auto b = rgb565 & 0x001F;
181  auto a = 0xFF;
182  switch (this->transparency_) {
184  a = progmem_read_byte(pos + 2);
185  break;
187  if (rgb565 == 0x0020)
188  a = 0;
189  break;
190  default:
191  break;
192  }
193  return Color((r << 3) | (r >> 2), (g << 2) | (g >> 4), (b << 3) | (b >> 2), a);
194 }
195 
197  const uint32_t pos = (x + y * this->width_);
198  const uint8_t gray = progmem_read_byte(this->data_start_ + pos);
199  switch (this->transparency_) {
201  if (gray == 1)
202  return Color(0, 0, 0, 0);
203  return Color(gray, gray, gray, 0xFF);
205  return Color(0, 0, 0, gray);
206  default:
207  return Color(gray, gray, gray, 0xFF);
208  }
209 }
210 int Image::get_width() const { return this->width_; }
211 int Image::get_height() const { return this->height_; }
212 ImageType Image::get_type() const { return this->type_; }
213 Image::Image(const uint8_t *data_start, int width, int height, ImageType type, Transparency transparency)
214  : width_(width), height_(height), type_(type), data_start_(data_start), transparency_(transparency) {
215  switch (this->type_) {
216  case IMAGE_TYPE_BINARY:
217  this->bpp_ = 1;
218  break;
220  this->bpp_ = 8;
221  break;
222  case IMAGE_TYPE_RGB565:
223  this->bpp_ = transparency == TRANSPARENCY_ALPHA_CHANNEL ? 24 : 16;
224  break;
225  case IMAGE_TYPE_RGB:
226  this->bpp_ = this->transparency_ == TRANSPARENCY_ALPHA_CHANNEL ? 32 : 24;
227  break;
228  }
229 }
230 
231 } // namespace image
232 } // namespace esphome
ImageType get_type() const
Definition: image.cpp:212
uint16_t x
Definition: tt21100.cpp:17
bool get_binary_pixel_(int x, int y) const
Definition: image.cpp:150
Color get_rgb_pixel_(int x, int y) const
Definition: image.cpp:155
Color get_pixel(int x, int y, Color color_on=display::COLOR_ON, Color color_off=display::COLOR_OFF) const
Definition: image.cpp:71
Color get_grayscale_pixel_(int x, int y) const
Definition: image.cpp:196
uint8_t g
Definition: color.h:18
uint16_t y
Definition: tt21100.cpp:18
ImageType type_
Definition: image.h:54
int get_width() const override
Definition: image.cpp:210
size_t get_width_stride() const
Return the stride of the image in bytes, that is, the distance in bytes between two consecutive rows ...
Definition: image.h:38
Color get_rgb565_pixel_(int x, int y) const
Definition: image.cpp:175
uint8_t type
constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit value given the most and least significant byte.
Definition: helpers.h:191
const uint8_t * data_start_
Definition: image.h:55
lv_img_dsc_t * get_lv_img_dsc()
Definition: image.cpp:90
uint8_t progmem_read_byte(const uint8_t *addr)
Definition: core.cpp:55
uint8_t w
Definition: color.h:26
Transparency transparency_
Definition: image.h:56
int get_height() const override
Definition: image.cpp:211
uint8_t b
Definition: color.h:22
void draw(int x, int y, display::Display *display, Color color_on, Color color_off) override
Definition: image.cpp:8
void draw_pixel_at(int x, int y)
Set a single pixel at the specified coordinates to default color.
Definition: display.h:226
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
uint8_t r
Definition: color.h:14
lv_img_dsc_t dsc_
Definition: image.h:60
Image(const uint8_t *data_start, int width, int height, ImageType type, Transparency transparency)
Definition: image.cpp:213