mirror of
https://github.com/esphome/esphome.git
synced 2026-10-14 10:12:52 +00:00
WIP: route opaque RGB565 and RGB images through draw_pixels_at
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
from esphome import automation
|
||||
import esphome.codegen as cg
|
||||
from esphome.components.const import CONF_LOOP
|
||||
from esphome.components.const import CONF_BYTE_ORDER, CONF_LOOP
|
||||
from esphome.components.file import image as file_image
|
||||
from esphome.components.file.image import image_schema, write_image
|
||||
from esphome.components.image import Image_, validate_settings
|
||||
@@ -115,6 +115,8 @@ async def setup_animation(config: ConfigType) -> None:
|
||||
image_type,
|
||||
trans_value,
|
||||
)
|
||||
if config.get(CONF_BYTE_ORDER) == "BIG_ENDIAN":
|
||||
cg.add(var.set_big_endian(True))
|
||||
if loop_config := config.get(CONF_LOOP):
|
||||
start = loop_config[CONF_START_FRAME]
|
||||
end = loop_config.get(CONF_END_FRAME, frame_count)
|
||||
|
||||
@@ -256,6 +256,8 @@ async def new_image(config: ConfigType) -> MockObj:
|
||||
var = cg.new_Pvariable(
|
||||
config[CONF_ID], prog_arr, width, height, image_type, trans_value
|
||||
)
|
||||
if config.get(CONF_BYTE_ORDER) == "BIG_ENDIAN":
|
||||
cg.add(var.set_big_endian(True))
|
||||
add_metadata(
|
||||
config[CONF_ID], width, height, config[CONF_TYPE], config[CONF_TRANSPARENCY]
|
||||
)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "image.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
|
||||
@@ -40,6 +42,29 @@ void Image::draw(int x, int y, display::Display *display, Color color_on, Color
|
||||
y_end = clipping.y2() - y;
|
||||
}
|
||||
|
||||
// Clamp to the display so the bulk path below never writes off screen; the
|
||||
// per pixel path bounds checks itself, this just saves it the work.
|
||||
if (x < 0)
|
||||
x_start = std::max(x_start, -x);
|
||||
if (y < 0)
|
||||
y_start = std::max(y_start, -y);
|
||||
x_end = std::min(x_end, display->get_width() - x);
|
||||
y_end = std::min(y_end, display->get_height() - y);
|
||||
if (x_end <= x_start || y_end <= y_start)
|
||||
return;
|
||||
|
||||
// Opaque RGB565 and RGB pixels are already in the layout draw_pixels_at()
|
||||
// takes, so hand the window to the display: drivers with a bulk path blit
|
||||
// it, the others walk it per pixel as before.
|
||||
if (this->transparency_ == TRANSPARENCY_OPAQUE &&
|
||||
(this->type_ == IMAGE_TYPE_RGB565 || this->type_ == IMAGE_TYPE_RGB)) {
|
||||
const bool rgb565 = this->type_ == IMAGE_TYPE_RGB565;
|
||||
display->draw_pixels_at(x + x_start, y + y_start, x_end - x_start, y_end - y_start, this->data_start_,
|
||||
display::COLOR_ORDER_RGB, rgb565 ? display::COLOR_BITNESS_565 : display::COLOR_BITNESS_888,
|
||||
rgb565 && this->big_endian_, x_start, y_start, this->width_ - x_end);
|
||||
return;
|
||||
}
|
||||
|
||||
// Pixel data and frame buffers are row-major, so walking rows keeps the
|
||||
// image read and the frame buffer write sequential. When the display swaps
|
||||
// the axes before writing, walking columns keeps the write sequential
|
||||
@@ -200,7 +225,8 @@ Color Image::get_rgb_pixel_(int x, int y) const {
|
||||
}
|
||||
Color Image::get_rgb565_pixel_(int x, int y) const {
|
||||
const uint8_t *pos = this->data_start_ + (x + y * this->width_) * this->bpp_ / 8;
|
||||
uint16_t rgb565 = encode_uint16(progmem_read_byte(pos + 1), progmem_read_byte(pos));
|
||||
const uint16_t rgb565 = this->big_endian_ ? encode_uint16(progmem_read_byte(pos), progmem_read_byte(pos + 1))
|
||||
: encode_uint16(progmem_read_byte(pos + 1), progmem_read_byte(pos));
|
||||
auto r = (rgb565 & 0xF800) >> 11;
|
||||
auto g = (rgb565 & 0x07E0) >> 5;
|
||||
auto b = rgb565 & 0x001F;
|
||||
|
||||
@@ -38,6 +38,8 @@ class Image : public display::BaseImage {
|
||||
void draw(int x, int y, display::Display *display, Color color_on, Color color_off) override;
|
||||
|
||||
bool has_transparency() const { return this->transparency_ != TRANSPARENCY_OPAQUE; }
|
||||
/// RGB565 pixel byte order; static images default to little endian.
|
||||
void set_big_endian(bool big_endian) { this->big_endian_ = big_endian; }
|
||||
|
||||
#ifdef USE_LVGL
|
||||
lv_image_dsc_t *get_lv_image_dsc();
|
||||
@@ -57,6 +59,7 @@ class Image : public display::BaseImage {
|
||||
ImageType type_;
|
||||
const uint8_t *data_start_;
|
||||
Transparency transparency_;
|
||||
bool big_endian_{false};
|
||||
size_t bpp_{};
|
||||
#ifdef USE_LVGL
|
||||
lv_img_dsc_t dsc_{};
|
||||
|
||||
@@ -189,8 +189,9 @@ class MipiSpi : public display::Display,
|
||||
if (w <= 0 || h <= 0)
|
||||
return;
|
||||
if (get_pixel_mode(bitness) != BUFFERPIXEL || big_endian != IS_BIG_ENDIAN) {
|
||||
// note that the usual logging macros are banned in header files, so use their replacement
|
||||
esph_log_e(TAG, "Unsupported color depth or bit order");
|
||||
// Not the buffer's own format: convert per pixel through draw_pixel_at()
|
||||
display::Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset,
|
||||
x_pad);
|
||||
return;
|
||||
}
|
||||
this->write_to_display_(x_start, y_start, w, h, reinterpret_cast<const BUFFERTYPE *>(ptr), x_offset, y_offset,
|
||||
|
||||
@@ -46,7 +46,9 @@ RuntimeImage::RuntimeImage(ImageFormat format, image::ImageType type, image::Tra
|
||||
fixed_width_(fixed_width),
|
||||
fixed_height_(fixed_height),
|
||||
placeholder_(placeholder),
|
||||
is_big_endian_(is_big_endian) {}
|
||||
is_big_endian_(is_big_endian) {
|
||||
this->big_endian_ = is_big_endian;
|
||||
}
|
||||
|
||||
RuntimeImage::~RuntimeImage() { this->release(); }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user