mirror of
https://github.com/esphome/esphome.git
synced 2024-11-26 17:05:21 +01:00
Image bit dephts (#1241)
This commit is contained in:
parent
32ae8fc2d0
commit
b7352b1345
3 changed files with 79 additions and 70 deletions
|
@ -204,31 +204,33 @@ void DisplayBuffer::vprintf_(int x, int y, Font *font, Color color, TextAlign al
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
this->print(x, y, font, color, align, buffer);
|
this->print(x, y, font, color, align, buffer);
|
||||||
}
|
}
|
||||||
void DisplayBuffer::image(int x, int y, Image *image) { this->image(x, y, COLOR_ON, image); }
|
|
||||||
void DisplayBuffer::image(int x, int y, Color color, Image *image, bool invert) {
|
void DisplayBuffer::image(int x, int y, Image *image, Color color_on, Color color_off) {
|
||||||
if (image->get_type() == BINARY) {
|
switch (image->get_type()) {
|
||||||
for (int img_x = 0; img_x < image->get_width(); img_x++) {
|
case IMAGE_TYPE_BINARY:
|
||||||
for (int img_y = 0; img_y < image->get_height(); img_y++) {
|
for (int img_x = 0; img_x < image->get_width(); img_x++) {
|
||||||
if (invert)
|
for (int img_y = 0; img_y < image->get_height(); img_y++) {
|
||||||
this->draw_pixel_at(x + img_x, y + img_y, image->get_pixel(img_x, img_y) ? COLOR_OFF : color);
|
this->draw_pixel_at(x + img_x, y + img_y, image->get_pixel(img_x, img_y) ? color_on : color_off);
|
||||||
else
|
}
|
||||||
this->draw_pixel_at(x + img_x, y + img_y, image->get_pixel(img_x, img_y) ? color : COLOR_OFF);
|
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
} else if (image->get_type() == GRAYSCALE) {
|
case IMAGE_TYPE_GRAYSCALE:
|
||||||
for (int img_x = 0; img_x < image->get_width(); img_x++) {
|
for (int img_x = 0; img_x < image->get_width(); img_x++) {
|
||||||
for (int img_y = 0; img_y < image->get_height(); img_y++) {
|
for (int img_y = 0; img_y < image->get_height(); img_y++) {
|
||||||
this->draw_pixel_at(x + img_x, y + img_y, image->get_grayscale_pixel(img_x, img_y));
|
this->draw_pixel_at(x + img_x, y + img_y, image->get_grayscale_pixel(img_x, img_y));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
} else if (image->get_type() == RGB) {
|
case IMAGE_TYPE_RGB24:
|
||||||
for (int img_x = 0; img_x < image->get_width(); img_x++) {
|
for (int img_x = 0; img_x < image->get_width(); img_x++) {
|
||||||
for (int img_y = 0; img_y < image->get_height(); img_y++) {
|
for (int img_y = 0; img_y < image->get_height(); img_y++) {
|
||||||
this->draw_pixel_at(x + img_x, y + img_y, image->get_color_pixel(img_x, img_y));
|
this->draw_pixel_at(x + img_x, y + img_y, image->get_color_pixel(img_x, img_y));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayBuffer::get_text_bounds(int x, int y, const char *text, Font *font, TextAlign align, int *x1, int *y1,
|
void DisplayBuffer::get_text_bounds(int x, int y, const char *text, Font *font, TextAlign align, int *x1, int *y1,
|
||||||
int *width, int *height) {
|
int *width, int *height) {
|
||||||
int x_offset, baseline;
|
int x_offset, baseline;
|
||||||
|
@ -463,15 +465,14 @@ Color Image::get_grayscale_pixel(int x, int y) const {
|
||||||
if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
|
if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
|
||||||
return 0;
|
return 0;
|
||||||
const uint32_t pos = (x + y * this->width_);
|
const uint32_t pos = (x + y * this->width_);
|
||||||
return Color(pgm_read_byte(this->data_start_ + pos) << 24);
|
const uint8_t gray = pgm_read_byte(this->data_start_ + pos);
|
||||||
|
return Color(gray | gray << 8 | gray << 16 | gray << 24);
|
||||||
}
|
}
|
||||||
int Image::get_width() const { return this->width_; }
|
int Image::get_width() const { return this->width_; }
|
||||||
int Image::get_height() const { return this->height_; }
|
int Image::get_height() const { return this->height_; }
|
||||||
ImageType Image::get_type() const { return this->type_; }
|
ImageType Image::get_type() const { return this->type_; }
|
||||||
Image::Image(const uint8_t *data_start, int width, int height)
|
Image::Image(const uint8_t *data_start, int width, int height, ImageType type)
|
||||||
: width_(width), height_(height), data_start_(data_start) {}
|
: width_(width), height_(height), type_(type), data_start_(data_start) {}
|
||||||
Image::Image(const uint8_t *data_start, int width, int height, int type)
|
|
||||||
: width_(width), height_(height), type_((ImageType) type), data_start_(data_start) {}
|
|
||||||
|
|
||||||
DisplayPage::DisplayPage(const display_writer_t &writer) : writer_(writer) {}
|
DisplayPage::DisplayPage(const display_writer_t &writer) : writer_(writer) {}
|
||||||
void DisplayPage::show() { this->parent_->show_page(this); }
|
void DisplayPage::show() { this->parent_->show_page(this); }
|
||||||
|
|
|
@ -68,7 +68,7 @@ extern const Color COLOR_OFF;
|
||||||
/// Turn the pixel ON.
|
/// Turn the pixel ON.
|
||||||
extern const Color COLOR_ON;
|
extern const Color COLOR_ON;
|
||||||
|
|
||||||
enum ImageType { BINARY = 0, GRAYSCALE = 1, RGB = 2 };
|
enum ImageType { IMAGE_TYPE_BINARY = 0, IMAGE_TYPE_GRAYSCALE = 1, IMAGE_TYPE_RGB24 = 2 };
|
||||||
|
|
||||||
enum DisplayRotation {
|
enum DisplayRotation {
|
||||||
DISPLAY_ROTATION_0_DEGREES = 0,
|
DISPLAY_ROTATION_0_DEGREES = 0,
|
||||||
|
@ -262,9 +262,15 @@ class DisplayBuffer {
|
||||||
__attribute__((format(strftime, 5, 0)));
|
__attribute__((format(strftime, 5, 0)));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// Draw the `image` with the top-left corner at [x,y] to the screen.
|
/** Draw the `image` with the top-left corner at [x,y] to the screen.
|
||||||
void image(int x, int y, Image *image);
|
*
|
||||||
void image(int x, int y, Color color, Image *image, bool invert = false);
|
* @param x The x coordinate of the upper left corner.
|
||||||
|
* @param y The y coordinate of the upper left corner.
|
||||||
|
* @param image The image to draw
|
||||||
|
* @param color_on The color to replace in binary images for the on bits.
|
||||||
|
* @param color_off The color to replace in binary images for the off bits.
|
||||||
|
*/
|
||||||
|
void image(int x, int y, Image *image, Color color_on = COLOR_ON, Color color_off = COLOR_OFF);
|
||||||
|
|
||||||
/** Get the text bounds of the given string.
|
/** Get the text bounds of the given string.
|
||||||
*
|
*
|
||||||
|
@ -381,8 +387,7 @@ class Font {
|
||||||
|
|
||||||
class Image {
|
class Image {
|
||||||
public:
|
public:
|
||||||
Image(const uint8_t *data_start, int width, int height);
|
Image(const uint8_t *data_start, int width, int height, ImageType type);
|
||||||
Image(const uint8_t *data_start, int width, int height, int type);
|
|
||||||
bool get_pixel(int x, int y) const;
|
bool get_pixel(int x, int y) const;
|
||||||
Color get_color_pixel(int x, int y) const;
|
Color get_color_pixel(int x, int y) const;
|
||||||
Color get_grayscale_pixel(int x, int y) const;
|
Color get_grayscale_pixel(int x, int y) const;
|
||||||
|
@ -393,7 +398,7 @@ class Image {
|
||||||
protected:
|
protected:
|
||||||
int width_;
|
int width_;
|
||||||
int height_;
|
int height_;
|
||||||
ImageType type_{BINARY};
|
ImageType type_;
|
||||||
const uint8_t *data_start_;
|
const uint8_t *data_start_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,14 +4,20 @@ from esphome import core
|
||||||
from esphome.components import display, font
|
from esphome.components import display, font
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
from esphome.const import CONF_FILE, CONF_ID, CONF_RESIZE, CONF_TYPE
|
from esphome.const import CONF_FILE, CONF_ID, CONF_TYPE, CONF_RESIZE
|
||||||
from esphome.core import CORE, HexInt
|
from esphome.core import CORE, HexInt
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
DEPENDENCIES = ['display']
|
DEPENDENCIES = ['display']
|
||||||
MULTI_CONF = True
|
MULTI_CONF = True
|
||||||
|
|
||||||
ImageType = {'binary': 0, 'grayscale': 1, 'rgb': 2}
|
|
||||||
|
ImageType = display.display_ns.enum('ImageType')
|
||||||
|
IMAGE_TYPE = {
|
||||||
|
'BINARY': ImageType.IMAGE_TYPE_BINARY,
|
||||||
|
'GRAYSCALE': ImageType.IMAGE_TYPE_GRAYSCALE,
|
||||||
|
'RGB24': ImageType.IMAGE_TYPE_RGB24,
|
||||||
|
}
|
||||||
|
|
||||||
Image_ = display.display_ns.class_('Image')
|
Image_ = display.display_ns.class_('Image')
|
||||||
|
|
||||||
|
@ -21,7 +27,7 @@ IMAGE_SCHEMA = cv.Schema({
|
||||||
cv.Required(CONF_ID): cv.declare_id(Image_),
|
cv.Required(CONF_ID): cv.declare_id(Image_),
|
||||||
cv.Required(CONF_FILE): cv.file_,
|
cv.Required(CONF_FILE): cv.file_,
|
||||||
cv.Optional(CONF_RESIZE): cv.dimensions,
|
cv.Optional(CONF_RESIZE): cv.dimensions,
|
||||||
cv.Optional(CONF_TYPE): cv.string,
|
cv.Optional(CONF_TYPE, default='BINARY'): cv.enum(IMAGE_TYPE, upper=True),
|
||||||
cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8),
|
cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -37,44 +43,40 @@ def to_code(config):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise core.EsphomeError(f"Could not load image file {path}: {e}")
|
raise core.EsphomeError(f"Could not load image file {path}: {e}")
|
||||||
|
|
||||||
|
width, height = image.size
|
||||||
|
|
||||||
if CONF_RESIZE in config:
|
if CONF_RESIZE in config:
|
||||||
image.thumbnail(config[CONF_RESIZE])
|
image.thumbnail(config[CONF_RESIZE])
|
||||||
|
|
||||||
if CONF_TYPE in config:
|
|
||||||
if config[CONF_TYPE].startswith('GRAYSCALE'):
|
|
||||||
width, height = image.size
|
|
||||||
image = image.convert('L', dither=Image.NONE)
|
|
||||||
pixels = list(image.getdata())
|
|
||||||
data = [0 for _ in range(height * width)]
|
|
||||||
pos = 0
|
|
||||||
for pix in pixels:
|
|
||||||
data[pos] = pix
|
|
||||||
pos += 1
|
|
||||||
rhs = [HexInt(x) for x in data]
|
|
||||||
prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
|
|
||||||
cg.new_Pvariable(config[CONF_ID], prog_arr, width, height, ImageType['grayscale'])
|
|
||||||
elif config[CONF_TYPE].startswith('RGB'):
|
|
||||||
width, height = image.size
|
|
||||||
image = image.convert('RGB')
|
|
||||||
pixels = list(image.getdata())
|
|
||||||
data = [0 for _ in range(height * width * 3)]
|
|
||||||
pos = 0
|
|
||||||
for pix in pixels:
|
|
||||||
data[pos] = pix[0]
|
|
||||||
pos += 1
|
|
||||||
data[pos] = pix[1]
|
|
||||||
pos += 1
|
|
||||||
data[pos] = pix[2]
|
|
||||||
pos += 1
|
|
||||||
rhs = [HexInt(x) for x in data]
|
|
||||||
prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
|
|
||||||
cg.new_Pvariable(config[CONF_ID], prog_arr, width, height, ImageType['rgb'])
|
|
||||||
else:
|
|
||||||
image = image.convert('1', dither=Image.NONE)
|
|
||||||
width, height = image.size
|
width, height = image.size
|
||||||
|
else:
|
||||||
if width > 500 or height > 500:
|
if width > 500 or height > 500:
|
||||||
_LOGGER.warning("The image you requested is very big. Please consider using"
|
_LOGGER.warning("The image you requested is very big. Please consider using"
|
||||||
" the resize parameter.")
|
" the resize parameter.")
|
||||||
|
|
||||||
|
if config[CONF_TYPE] == 'GRAYSCALE':
|
||||||
|
image = image.convert('L', dither=Image.NONE)
|
||||||
|
pixels = list(image.getdata())
|
||||||
|
data = [0 for _ in range(height * width)]
|
||||||
|
pos = 0
|
||||||
|
for pix in pixels:
|
||||||
|
data[pos] = pix
|
||||||
|
pos += 1
|
||||||
|
|
||||||
|
elif config[CONF_TYPE] == 'RGB24':
|
||||||
|
image = image.convert('RGB')
|
||||||
|
pixels = list(image.getdata())
|
||||||
|
data = [0 for _ in range(height * width * 3)]
|
||||||
|
pos = 0
|
||||||
|
for pix in pixels:
|
||||||
|
data[pos] = pix[0]
|
||||||
|
pos += 1
|
||||||
|
data[pos] = pix[1]
|
||||||
|
pos += 1
|
||||||
|
data[pos] = pix[2]
|
||||||
|
pos += 1
|
||||||
|
|
||||||
|
elif config[CONF_TYPE] == 'BINARY':
|
||||||
|
image = image.convert('1', dither=Image.NONE)
|
||||||
width8 = ((width + 7) // 8) * 8
|
width8 = ((width + 7) // 8) * 8
|
||||||
data = [0 for _ in range(height * width8 // 8)]
|
data = [0 for _ in range(height * width8 // 8)]
|
||||||
for y in range(height):
|
for y in range(height):
|
||||||
|
@ -84,6 +86,7 @@ def to_code(config):
|
||||||
pos = x + y * width8
|
pos = x + y * width8
|
||||||
data[pos // 8] |= 0x80 >> (pos % 8)
|
data[pos // 8] |= 0x80 >> (pos % 8)
|
||||||
|
|
||||||
rhs = [HexInt(x) for x in data]
|
rhs = [HexInt(x) for x in data]
|
||||||
prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
|
prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
|
||||||
cg.new_Pvariable(config[CONF_ID], prog_arr, width, height)
|
cg.new_Pvariable(config[CONF_ID], prog_arr, width, height,
|
||||||
|
IMAGE_TYPE[config[CONF_TYPE]])
|
||||||
|
|
Loading…
Reference in a new issue