mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	Image bit dephts (#1241)
This commit is contained in:
		| @@ -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]]) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user