ESPHome  2024.10.2
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->transparent_) {
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  auto color = this->get_grayscale_pixel_(img_x, img_y);
26  if (color.w >= 0x80) {
27  display->draw_pixel_at(x + img_x, y + img_y, color);
28  }
29  }
30  }
31  break;
32  case IMAGE_TYPE_RGB565:
33  for (int img_x = 0; img_x < width_; img_x++) {
34  for (int img_y = 0; img_y < height_; img_y++) {
35  auto color = this->get_rgb565_pixel_(img_x, img_y);
36  if (color.w >= 0x80) {
37  display->draw_pixel_at(x + img_x, y + img_y, color);
38  }
39  }
40  }
41  break;
42  case IMAGE_TYPE_RGB24:
43  for (int img_x = 0; img_x < width_; img_x++) {
44  for (int img_y = 0; img_y < height_; img_y++) {
45  auto color = this->get_rgb24_pixel_(img_x, img_y);
46  if (color.w >= 0x80) {
47  display->draw_pixel_at(x + img_x, y + img_y, color);
48  }
49  }
50  }
51  break;
52  case IMAGE_TYPE_RGBA:
53  for (int img_x = 0; img_x < width_; img_x++) {
54  for (int img_y = 0; img_y < height_; img_y++) {
55  auto color = this->get_rgba_pixel_(img_x, img_y);
56  if (color.w >= 0x80) {
57  display->draw_pixel_at(x + img_x, y + img_y, color);
58  }
59  }
60  }
61  break;
62  }
63 }
64 Color Image::get_pixel(int x, int y, Color color_on, Color color_off) const {
65  if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
66  return color_off;
67  switch (this->type_) {
68  case IMAGE_TYPE_BINARY:
69  return this->get_binary_pixel_(x, y) ? color_on : color_off;
71  return this->get_grayscale_pixel_(x, y);
72  case IMAGE_TYPE_RGB565:
73  return this->get_rgb565_pixel_(x, y);
74  case IMAGE_TYPE_RGB24:
75  return this->get_rgb24_pixel_(x, y);
76  case IMAGE_TYPE_RGBA:
77  return this->get_rgba_pixel_(x, y);
78  default:
79  return color_off;
80  }
81 }
82 #ifdef USE_LVGL
83 lv_img_dsc_t *Image::get_lv_img_dsc() {
84  // lazily construct lvgl image_dsc.
85  if (this->dsc_.data != this->data_start_) {
86  this->dsc_.data = this->data_start_;
87  this->dsc_.header.always_zero = 0;
88  this->dsc_.header.reserved = 0;
89  this->dsc_.header.w = this->width_;
90  this->dsc_.header.h = this->height_;
91  this->dsc_.data_size = image_type_to_width_stride(this->dsc_.header.w * this->dsc_.header.h, this->get_type());
92  switch (this->get_type()) {
93  case IMAGE_TYPE_BINARY:
94  this->dsc_.header.cf = LV_IMG_CF_ALPHA_1BIT;
95  break;
96 
98  this->dsc_.header.cf = LV_IMG_CF_ALPHA_8BIT;
99  break;
100 
101  case IMAGE_TYPE_RGB24:
102  this->dsc_.header.cf = LV_IMG_CF_RGB888;
103  break;
104 
105  case IMAGE_TYPE_RGB565:
106 #if LV_COLOR_DEPTH == 16
107  this->dsc_.header.cf = this->has_transparency() ? LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED : LV_IMG_CF_TRUE_COLOR;
108 #else
109  this->dsc_.header.cf = LV_IMG_CF_RGB565;
110 #endif
111  break;
112 
114 #if LV_COLOR_DEPTH == 32
115  this->dsc_.header.cf = LV_IMG_CF_TRUE_COLOR;
116 #else
117  this->dsc_.header.cf = LV_IMG_CF_RGBA8888;
118 #endif
119  break;
120  }
121  }
122  return &this->dsc_;
123 }
124 #endif // USE_LVGL
125 
126 bool Image::get_binary_pixel_(int x, int y) const {
127  const uint32_t width_8 = ((this->width_ + 7u) / 8u) * 8u;
128  const uint32_t pos = x + y * width_8;
129  return progmem_read_byte(this->data_start_ + (pos / 8u)) & (0x80 >> (pos % 8u));
130 }
131 Color Image::get_rgba_pixel_(int x, int y) const {
132  const uint32_t pos = (x + y * this->width_) * 4;
133  return Color(progmem_read_byte(this->data_start_ + pos + 0), progmem_read_byte(this->data_start_ + pos + 1),
134  progmem_read_byte(this->data_start_ + pos + 2), progmem_read_byte(this->data_start_ + pos + 3));
135 }
136 Color Image::get_rgb24_pixel_(int x, int y) const {
137  const uint32_t pos = (x + y * this->width_) * 3;
138  Color color = Color(progmem_read_byte(this->data_start_ + pos + 0), progmem_read_byte(this->data_start_ + pos + 1),
139  progmem_read_byte(this->data_start_ + pos + 2));
140  if (color.b == 1 && color.r == 0 && color.g == 0 && transparent_) {
141  // (0, 0, 1) has been defined as transparent color for non-alpha images.
142  // putting blue == 1 as a first condition for performance reasons (least likely value to short-cut the if)
143  color.w = 0;
144  } else {
145  color.w = 0xFF;
146  }
147  return color;
148 }
150  const uint32_t pos = (x + y * this->width_) * 2;
151  uint16_t rgb565 =
152  progmem_read_byte(this->data_start_ + pos + 0) << 8 | progmem_read_byte(this->data_start_ + pos + 1);
153  auto r = (rgb565 & 0xF800) >> 11;
154  auto g = (rgb565 & 0x07E0) >> 5;
155  auto b = rgb565 & 0x001F;
156  Color color = Color((r << 3) | (r >> 2), (g << 2) | (g >> 4), (b << 3) | (b >> 2));
157  if (rgb565 == 0x0020 && transparent_) {
158  // darkest green has been defined as transparent color for transparent RGB565 images.
159  color.w = 0;
160  } else {
161  color.w = 0xFF;
162  }
163  return color;
164 }
166  const uint32_t pos = (x + y * this->width_);
167  const uint8_t gray = progmem_read_byte(this->data_start_ + pos);
168  uint8_t alpha = (gray == 1 && transparent_) ? 0 : 0xFF;
169  return Color(gray, gray, gray, alpha);
170 }
171 int Image::get_width() const { return this->width_; }
172 int Image::get_height() const { return this->height_; }
173 ImageType Image::get_type() const { return this->type_; }
174 Image::Image(const uint8_t *data_start, int width, int height, ImageType type)
175  : width_(width), height_(height), type_(type), data_start_(data_start) {}
176 
177 } // namespace image
178 } // namespace esphome
bool has_transparency() const
Definition: image.h:55
int image_type_to_width_stride(int width, ImageType type)
Definition: image.h:41
ImageType get_type() const
Definition: image.cpp:173
Color get_rgb24_pixel_(int x, int y) const
Definition: image.cpp:136
uint16_t x
Definition: tt21100.cpp:17
bool get_binary_pixel_(int x, int y) const
Definition: image.cpp:126
Color get_pixel(int x, int y, Color color_on=display::COLOR_ON, Color color_off=display::COLOR_OFF) const
Definition: image.cpp:64
Color get_grayscale_pixel_(int x, int y) const
Definition: image.cpp:165
uint8_t g
Definition: color.h:18
uint16_t y
Definition: tt21100.cpp:18
ImageType type_
Definition: image.h:69
int get_width() const override
Definition: image.cpp:171
Color get_rgb565_pixel_(int x, int y) const
Definition: image.cpp:149
uint8_t type
const uint8_t * data_start_
Definition: image.h:70
lv_img_dsc_t * get_lv_img_dsc()
Definition: image.cpp:83
uint8_t progmem_read_byte(const uint8_t *addr)
Definition: core.cpp:55
uint8_t w
Definition: color.h:26
int get_height() const override
Definition: image.cpp:172
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:73
Image(const uint8_t *data_start, int width, int height, ImageType type)
Definition: image.cpp:174
Color get_rgba_pixel_(int x, int y) const
Definition: image.cpp:131