15template<
bool ROWS_OUTER,
typename F>
16static void for_each_pixel(
int x_start,
int x_end,
int y_start,
int y_end,
int width, F &&f) {
17 const int outer_start = ROWS_OUTER ? y_start : x_start;
18 const int outer_end = ROWS_OUTER ? y_end : x_end;
19 const int inner_start = ROWS_OUTER ? x_start : y_start;
20 const int inner_end = ROWS_OUTER ? x_end : y_end;
21 for (
int outer = outer_start; outer < outer_end; outer++) {
22 const int outer_pos = ROWS_OUTER ? outer * width : outer;
23 for (
int inner = inner_start; inner < inner_end; inner++) {
24 f(ROWS_OUTER ? inner : outer, ROWS_OUTER ? outer : inner,
25 ROWS_OUTER ? outer_pos + inner : outer_pos + inner * width);
37 if (clipping.is_set()) {
39 x_start += clipping.x -
x;
41 y_start += clipping.y -
y;
42 if (x_end > clipping.x2() -
x)
43 x_end = clipping.x2() -
x;
44 if (y_end > clipping.y2() -
y)
45 y_end = clipping.y2() -
y;
54 x_start = std::max(x_start, -
x);
55 y_start = std::max(y_start, -
y);
56 x_end = std::min(x_end, display->
get_width() -
x);
58 if (x_end <= x_start || y_end <= y_start)
63 x_start, y_start, this->
width_ - x_end);
72 this->
draw_<false>(x,
y, display, color_on, color_off, x_start, x_end, y_start, y_end);
77 this->
draw_<true>(x,
y, display, color_on, color_off, x_start, x_end, y_start, y_end);
80template<
bool ROWS_OUTER>
82 int y_start,
int y_end) {
85 const int width = this->
width_;
86 switch (this->
type_) {
88 for_each_pixel<ROWS_OUTER>(x_start, x_end, y_start, y_end, width,
89 [&](
int img_x,
int img_y,
int pos) ESPHOME_ALWAYS_INLINE {
98 for_each_pixel<ROWS_OUTER>(x_start, x_end, y_start, y_end, width,
99 [&](
int img_x,
int img_y,
int pos) ESPHOME_ALWAYS_INLINE {
101 if (color.w >= 0x80) {
108 for_each_pixel<ROWS_OUTER>(x_start, x_end, y_start, y_end, width,
109 [&](
int img_x,
int img_y,
int pos) ESPHOME_ALWAYS_INLINE {
127 for_each_pixel<ROWS_OUTER>(x_start, x_end, y_start, y_end, width,
128 [&](
int img_x,
int img_y,
int pos) ESPHOME_ALWAYS_INLINE {
130 if (color.w >= 0x80) {
136 for_each_pixel<ROWS_OUTER>(x_start, x_end, y_start, y_end, width,
137 [&](
int img_x,
int img_y,
int pos) ESPHOME_ALWAYS_INLINE {
139 if (color.w >= 0x80) {
149 switch (this->
type_) {
169 if (this->
dsc_.data != this->data_start_) {
171 this->
dsc_.header.reserved_2 = 0;
178 this->
dsc_.header.cf = LV_COLOR_FORMAT_A1;
182 this->
dsc_.header.cf = LV_COLOR_FORMAT_A8;
187 ESP_LOGE(TAG,
"RGB111 images are not supported in LVGL.");
192 this->
dsc_.header.cf = LV_COLOR_FORMAT_ARGB8888;
196 this->
dsc_.header.cf = LV_COLOR_FORMAT_RGB888;
204 this->
dsc_.header.cf = LV_COLOR_FORMAT_RGB565A8;
207 this->
dsc_.header.cf = LV_COLOR_FORMAT_RGB565;
223 const uint8_t *
byte = this->
data_start_ + bitpos / 8;
224 const uint8_t shift = bitpos % 8;
227 if (shift + this->bpp_ > 8)
229 const uint8_t bits = (window >> (16 - this->bpp_ - shift)) & ((1u << this->bpp_) - 1);
230 const uint8_t rgb = this->bpp_ == 4 ? bits >> 1 : bits;
231 const bool opaque = this->bpp_ == 3 || (bits & 1);
232 return Color(rgb & 4 ? 0xFF : 0x00, rgb & 2 ? 0xFF : 0x00, rgb & 1 ? 0xFF : 0x00, opaque ? 0xFF : 0x00);
241 if (color.
g == 1 && color.
r == 0 && color.
b == 0) {
259 auto r = (rgb565 & 0xF800) >> 11;
260 auto g = (rgb565 & 0x07E0) >> 5;
261 auto b = rgb565 & 0x001F;
268 if (rgb565 == 0x0020)
274 return Color((r << 3) | (r >> 2), (g << 2) | (g >> 4), (b << 3) | (b >> 2), a);
283 return Color(0, 0, 0, 0);
284 return Color(gray, gray, gray, 0xFF);
286 return Color(0, 0, 0, gray);
288 return Color(gray, gray, gray, 0xFF);
299 data_start_(data_start),
300 transparency_(transparency),
301 big_endian_(big_endian) {
302 switch (this->
type_) {
virtual bool pixel_axes_swapped() const
True when draw_pixel_at() swaps x and y before writing, so pixels that are neighbours along x land a ...
virtual int get_height()
Get the calculated height of the display in pixels with rotation applied.
virtual int get_width()
Get the calculated width of the display in pixels with rotation applied.
void draw_pixel_at(int x, int y)
Set a single pixel at the specified coordinates to default color.
void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad)
Given an array of pixels encoded in the nominated format, draw these into the display's buffer.
Rect get_clipping() const
Get the current the clipping rectangle.
Color get_rgb565_pixel_(int x, int y) const
const uint8_t * data_start_
Color get_rgb_pixel_(int x, int y) const
size_t get_width_stride() const
Return the stride of the image in bytes, that is, the distance in bytes between two consecutive rows ...
Color get_pixel(int x, int y, Color color_on=display::COLOR_ON, Color color_off=display::COLOR_OFF) const
int get_height() const override
ImageType get_type() const
bool get_binary_pixel_(int x, int y) const
Image(const uint8_t *data_start, int width, int height, ImageType type, Transparency transparency, bool big_endian=false)
big_endian is the RGB565 byte order; codegen writes little endian unless configured otherwise.
void draw_(int x, int y, display::Display *display, Color color_on, Color color_off, int x_start, int x_end, int y_start, int y_end)
Per-pixel draw of the clipped range, rows (true) or columns (false) outer.
Transparency transparency_
Color get_rgb111_pixel_(int x, int y) const
lv_image_dsc_t * get_lv_image_dsc()
void draw(int x, int y, display::Display *display, Color color_on, Color color_off) override
int get_width() const override
Color get_grayscale_pixel_(int x, int y) const
ESPHOME_LOG_TAG(TAG, "image")
@ TRANSPARENCY_ALPHA_CHANNEL
@ TRANSPARENCY_CHROMA_KEY
constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit value given the most and least significant byte.
uint8_t progmem_read_byte(const uint8_t *addr)
static uint8_t blend_channel(uint8_t from, uint8_t to, uint8_t amnt) ESPHOME_ALWAYS_INLINE
One channel of gradient(): from at amnt 0 to to at amnt 255.