mirror of
https://github.com/esphome/esphome.git
synced 2024-11-21 11:37:27 +01:00
[image][online_image][animation] Fix transparency in RGB565 (#7631)
This commit is contained in:
parent
09f9d91577
commit
33fdbbe30c
@ -271,7 +271,8 @@ async def to_code(config):
|
||||
pos += 1
|
||||
|
||||
elif config[CONF_TYPE] in ["RGB565", "TRANSPARENT_IMAGE"]:
|
||||
data = [0 for _ in range(height * width * 2 * frames)]
|
||||
bytes_per_pixel = 3 if transparent else 2
|
||||
data = [0 for _ in range(height * width * bytes_per_pixel * frames)]
|
||||
pos = 0
|
||||
for frameIndex in range(frames):
|
||||
image.seek(frameIndex)
|
||||
@ -288,17 +289,13 @@ async def to_code(config):
|
||||
G = g >> 2
|
||||
B = b >> 3
|
||||
rgb = (R << 11) | (G << 5) | B
|
||||
|
||||
if transparent:
|
||||
if rgb == 0x0020:
|
||||
rgb = 0
|
||||
if a < 0x80:
|
||||
rgb = 0x0020
|
||||
|
||||
data[pos] = rgb >> 8
|
||||
pos += 1
|
||||
data[pos] = rgb & 0xFF
|
||||
pos += 1
|
||||
if transparent:
|
||||
data[pos] = a
|
||||
pos += 1
|
||||
|
||||
elif config[CONF_TYPE] in ["BINARY", "TRANSPARENT_BINARY"]:
|
||||
width8 = ((width + 7) // 8) * 8
|
||||
|
@ -62,7 +62,7 @@ void Animation::set_frame(int frame) {
|
||||
}
|
||||
|
||||
void Animation::update_data_start_() {
|
||||
const uint32_t image_size = image_type_to_width_stride(this->width_, this->type_) * this->height_;
|
||||
const uint32_t image_size = this->get_width_stride() * this->height_;
|
||||
this->data_start_ = this->animation_data_start_ + image_size * this->current_frame_;
|
||||
}
|
||||
|
||||
|
@ -361,24 +361,21 @@ async def to_code(config):
|
||||
elif config[CONF_TYPE] in ["RGB565"]:
|
||||
image = image.convert("RGBA")
|
||||
pixels = list(image.getdata())
|
||||
data = [0 for _ in range(height * width * 2)]
|
||||
bytes_per_pixel = 3 if transparent else 2
|
||||
data = [0 for _ in range(height * width * bytes_per_pixel)]
|
||||
pos = 0
|
||||
for r, g, b, a in pixels:
|
||||
R = r >> 3
|
||||
G = g >> 2
|
||||
B = b >> 3
|
||||
rgb = (R << 11) | (G << 5) | B
|
||||
|
||||
if transparent:
|
||||
if rgb == 0x0020:
|
||||
rgb = 0
|
||||
if a < 0x80:
|
||||
rgb = 0x0020
|
||||
|
||||
data[pos] = rgb >> 8
|
||||
pos += 1
|
||||
data[pos] = rgb & 0xFF
|
||||
pos += 1
|
||||
if transparent:
|
||||
data[pos] = a
|
||||
pos += 1
|
||||
|
||||
elif config[CONF_TYPE] in ["BINARY", "TRANSPARENT_BINARY"]:
|
||||
if transparent:
|
||||
|
@ -88,7 +88,7 @@ lv_img_dsc_t *Image::get_lv_img_dsc() {
|
||||
this->dsc_.header.reserved = 0;
|
||||
this->dsc_.header.w = this->width_;
|
||||
this->dsc_.header.h = this->height_;
|
||||
this->dsc_.data_size = image_type_to_width_stride(this->dsc_.header.w * this->dsc_.header.h, this->get_type());
|
||||
this->dsc_.data_size = this->get_width_stride() * this->get_height();
|
||||
switch (this->get_type()) {
|
||||
case IMAGE_TYPE_BINARY:
|
||||
this->dsc_.header.cf = LV_IMG_CF_ALPHA_1BIT;
|
||||
@ -104,17 +104,17 @@ lv_img_dsc_t *Image::get_lv_img_dsc() {
|
||||
|
||||
case IMAGE_TYPE_RGB565:
|
||||
#if LV_COLOR_DEPTH == 16
|
||||
this->dsc_.header.cf = this->has_transparency() ? LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED : LV_IMG_CF_TRUE_COLOR;
|
||||
this->dsc_.header.cf = this->has_transparency() ? LV_IMG_CF_TRUE_COLOR_ALPHA : LV_IMG_CF_TRUE_COLOR;
|
||||
#else
|
||||
this->dsc_.header.cf = LV_IMG_CF_RGB565;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case image::IMAGE_TYPE_RGBA:
|
||||
case IMAGE_TYPE_RGBA:
|
||||
#if LV_COLOR_DEPTH == 32
|
||||
this->dsc_.header.cf = LV_IMG_CF_TRUE_COLOR;
|
||||
#else
|
||||
this->dsc_.header.cf = LV_IMG_CF_RGBA8888;
|
||||
this->dsc_.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@ -147,21 +147,21 @@ Color Image::get_rgb24_pixel_(int x, int y) const {
|
||||
return color;
|
||||
}
|
||||
Color Image::get_rgb565_pixel_(int x, int y) const {
|
||||
const uint32_t pos = (x + y * this->width_) * 2;
|
||||
uint16_t rgb565 =
|
||||
progmem_read_byte(this->data_start_ + pos + 0) << 8 | progmem_read_byte(this->data_start_ + pos + 1);
|
||||
const uint8_t *pos = this->data_start_;
|
||||
if (this->transparent_) {
|
||||
pos += (x + y * this->width_) * 3;
|
||||
} else {
|
||||
pos += (x + y * this->width_) * 2;
|
||||
}
|
||||
uint16_t rgb565 = encode_uint16(progmem_read_byte(pos), progmem_read_byte(pos + 1));
|
||||
auto r = (rgb565 & 0xF800) >> 11;
|
||||
auto g = (rgb565 & 0x07E0) >> 5;
|
||||
auto b = rgb565 & 0x001F;
|
||||
Color color = Color((r << 3) | (r >> 2), (g << 2) | (g >> 4), (b << 3) | (b >> 2));
|
||||
if (rgb565 == 0x0020 && transparent_) {
|
||||
// darkest green has been defined as transparent color for transparent RGB565 images.
|
||||
color.w = 0;
|
||||
} else {
|
||||
color.w = 0xFF;
|
||||
}
|
||||
auto a = this->transparent_ ? progmem_read_byte(pos + 2) : 0xFF;
|
||||
Color color = Color((r << 3) | (r >> 2), (g << 2) | (g >> 4), (b << 3) | (b >> 2), a);
|
||||
return color;
|
||||
}
|
||||
|
||||
Color Image::get_grayscale_pixel_(int x, int y) const {
|
||||
const uint32_t pos = (x + y * this->width_);
|
||||
const uint8_t gray = progmem_read_byte(this->data_start_ + pos);
|
||||
|
@ -17,24 +17,6 @@ enum ImageType {
|
||||
IMAGE_TYPE_RGBA = 4,
|
||||
};
|
||||
|
||||
inline int image_type_to_bpp(ImageType type) {
|
||||
switch (type) {
|
||||
case IMAGE_TYPE_BINARY:
|
||||
return 1;
|
||||
case IMAGE_TYPE_GRAYSCALE:
|
||||
return 8;
|
||||
case IMAGE_TYPE_RGB565:
|
||||
return 16;
|
||||
case IMAGE_TYPE_RGB24:
|
||||
return 24;
|
||||
case IMAGE_TYPE_RGBA:
|
||||
return 32;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int image_type_to_width_stride(int width, ImageType type) { return (width * image_type_to_bpp(type) + 7u) / 8u; }
|
||||
|
||||
class Image : public display::BaseImage {
|
||||
public:
|
||||
Image(const uint8_t *data_start, int width, int height, ImageType type);
|
||||
@ -44,6 +26,25 @@ class Image : public display::BaseImage {
|
||||
const uint8_t *get_data_start() const { return this->data_start_; }
|
||||
ImageType get_type() const;
|
||||
|
||||
int get_bpp() const {
|
||||
switch (this->type_) {
|
||||
case IMAGE_TYPE_BINARY:
|
||||
return 1;
|
||||
case IMAGE_TYPE_GRAYSCALE:
|
||||
return 8;
|
||||
case IMAGE_TYPE_RGB565:
|
||||
return this->transparent_ ? 24 : 16;
|
||||
case IMAGE_TYPE_RGB24:
|
||||
return 24;
|
||||
case IMAGE_TYPE_RGBA:
|
||||
return 32;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Return the stride of the image in bytes, that is, the distance in bytes
|
||||
/// between two consecutive rows of pixels.
|
||||
uint32_t get_width_stride() const { return (this->width_ * this->get_bpp() + 7u) / 8u; }
|
||||
void draw(int x, int y, display::Display *display, Color color_on, Color color_off) override;
|
||||
|
||||
void set_transparency(bool transparent) { transparent_ = transparent; }
|
||||
|
@ -215,16 +215,10 @@ void OnlineImage::draw_pixel_(int x, int y, Color color) {
|
||||
}
|
||||
case ImageType::IMAGE_TYPE_RGB565: {
|
||||
uint16_t col565 = display::ColorUtil::color_to_565(color);
|
||||
if (this->has_transparency()) {
|
||||
if (col565 == 0x0020) {
|
||||
col565 = 0;
|
||||
}
|
||||
if (color.w < 0x80) {
|
||||
col565 = 0x0020;
|
||||
}
|
||||
}
|
||||
this->buffer_[pos + 0] = static_cast<uint8_t>((col565 >> 8) & 0xFF);
|
||||
this->buffer_[pos + 1] = static_cast<uint8_t>(col565 & 0xFF);
|
||||
if (this->has_transparency())
|
||||
this->buffer_[pos + 2] = color.w;
|
||||
break;
|
||||
}
|
||||
case ImageType::IMAGE_TYPE_RGBA: {
|
||||
|
@ -86,13 +86,9 @@ class OnlineImage : public PollingComponent,
|
||||
Allocator allocator_{Allocator::Flags::ALLOW_FAILURE};
|
||||
|
||||
uint32_t get_buffer_size_() const { return get_buffer_size_(this->buffer_width_, this->buffer_height_); }
|
||||
int get_buffer_size_(int width, int height) const {
|
||||
return std::ceil(image::image_type_to_bpp(this->type_) * width * height / 8.0);
|
||||
}
|
||||
int get_buffer_size_(int width, int height) const { return (this->get_bpp() * width + 7u) / 8u * height; }
|
||||
|
||||
int get_position_(int x, int y) const {
|
||||
return ((x + y * this->buffer_width_) * image::image_type_to_bpp(this->type_)) / 8;
|
||||
}
|
||||
int get_position_(int x, int y) const { return (x + y * this->buffer_width_) * this->get_bpp() / 8; }
|
||||
|
||||
ESPHOME_ALWAYS_INLINE bool auto_resize_() const { return this->fixed_width_ == 0 || this->fixed_height_ == 0; }
|
||||
|
||||
|
38
tests/components/image/common.yaml
Normal file
38
tests/components/image/common.yaml
Normal file
@ -0,0 +1,38 @@
|
||||
image:
|
||||
- id: binary_image
|
||||
file: ../../pnglogo.png
|
||||
type: BINARY
|
||||
dither: FloydSteinberg
|
||||
- id: transparent_transparent_image
|
||||
file: ../../pnglogo.png
|
||||
type: TRANSPARENT_BINARY
|
||||
- id: rgba_image
|
||||
file: ../../pnglogo.png
|
||||
type: RGBA
|
||||
resize: 50x50
|
||||
- id: rgb24_image
|
||||
file: ../../pnglogo.png
|
||||
type: RGB24
|
||||
use_transparency: yes
|
||||
- id: rgb565_image
|
||||
file: ../../pnglogo.png
|
||||
type: RGB565
|
||||
use_transparency: no
|
||||
- id: web_svg_image
|
||||
file: https://raw.githubusercontent.com/esphome/esphome-docs/a62d7ab193c1a464ed791670170c7d518189109b/images/logo.svg
|
||||
resize: 256x48
|
||||
type: TRANSPARENT_BINARY
|
||||
- id: web_tiff_image
|
||||
file: https://upload.wikimedia.org/wikipedia/commons/b/b6/SIPI_Jelly_Beans_4.1.07.tiff
|
||||
type: RGB24
|
||||
resize: 48x48
|
||||
- id: web_redirect_image
|
||||
file: https://avatars.githubusercontent.com/u/3060199?s=48&v=4
|
||||
type: RGB24
|
||||
resize: 48x48
|
||||
- id: mdi_alert
|
||||
file: mdi:alert-circle-outline
|
||||
resize: 50x50
|
||||
- id: another_alert_icon
|
||||
file: mdi:alert-outline
|
||||
type: BINARY
|
@ -13,41 +13,5 @@ display:
|
||||
reset_pin: 21
|
||||
invert_colors: true
|
||||
|
||||
image:
|
||||
- id: binary_image
|
||||
file: ../../pnglogo.png
|
||||
type: BINARY
|
||||
dither: FloydSteinberg
|
||||
- id: transparent_transparent_image
|
||||
file: ../../pnglogo.png
|
||||
type: TRANSPARENT_BINARY
|
||||
- id: rgba_image
|
||||
file: ../../pnglogo.png
|
||||
type: RGBA
|
||||
resize: 50x50
|
||||
- id: rgb24_image
|
||||
file: ../../pnglogo.png
|
||||
type: RGB24
|
||||
use_transparency: yes
|
||||
- id: rgb565_image
|
||||
file: ../../pnglogo.png
|
||||
type: RGB565
|
||||
use_transparency: no
|
||||
- id: web_svg_image
|
||||
file: https://raw.githubusercontent.com/esphome/esphome-docs/a62d7ab193c1a464ed791670170c7d518189109b/images/logo.svg
|
||||
resize: 256x48
|
||||
type: TRANSPARENT_BINARY
|
||||
- id: web_tiff_image
|
||||
file: https://upload.wikimedia.org/wikipedia/commons/b/b6/SIPI_Jelly_Beans_4.1.07.tiff
|
||||
type: RGB24
|
||||
resize: 48x48
|
||||
- id: web_redirect_image
|
||||
file: https://avatars.githubusercontent.com/u/3060199?s=48&v=4
|
||||
type: RGB24
|
||||
resize: 48x48
|
||||
- id: mdi_alert
|
||||
file: mdi:alert-circle-outline
|
||||
resize: 50x50
|
||||
- id: another_alert_icon
|
||||
file: mdi:alert-outline
|
||||
type: BINARY
|
||||
<<: !include common.yaml
|
||||
|
||||
|
@ -13,41 +13,4 @@ display:
|
||||
reset_pin: 10
|
||||
invert_colors: true
|
||||
|
||||
image:
|
||||
- id: binary_image
|
||||
file: ../../pnglogo.png
|
||||
type: BINARY
|
||||
dither: FloydSteinberg
|
||||
- id: transparent_transparent_image
|
||||
file: ../../pnglogo.png
|
||||
type: TRANSPARENT_BINARY
|
||||
- id: rgba_image
|
||||
file: ../../pnglogo.png
|
||||
type: RGBA
|
||||
resize: 50x50
|
||||
- id: rgb24_image
|
||||
file: ../../pnglogo.png
|
||||
type: RGB24
|
||||
use_transparency: yes
|
||||
- id: rgb565_image
|
||||
file: ../../pnglogo.png
|
||||
type: RGB565
|
||||
use_transparency: no
|
||||
- id: web_svg_image
|
||||
file: https://raw.githubusercontent.com/esphome/esphome-docs/a62d7ab193c1a464ed791670170c7d518189109b/images/logo.svg
|
||||
resize: 256x48
|
||||
type: TRANSPARENT_BINARY
|
||||
- id: web_tiff_image
|
||||
file: https://upload.wikimedia.org/wikipedia/commons/b/b6/SIPI_Jelly_Beans_4.1.07.tiff
|
||||
type: RGB24
|
||||
resize: 48x48
|
||||
- id: web_redirect_image
|
||||
file: https://avatars.githubusercontent.com/u/3060199?s=48&v=4
|
||||
type: RGB24
|
||||
resize: 48x48
|
||||
- id: mdi_alert
|
||||
file: mdi:alert-circle-outline
|
||||
resize: 50x50
|
||||
- id: another_alert_icon
|
||||
file: mdi:alert-outline
|
||||
type: BINARY
|
||||
<<: !include common.yaml
|
||||
|
@ -13,41 +13,4 @@ display:
|
||||
reset_pin: 10
|
||||
invert_colors: true
|
||||
|
||||
image:
|
||||
- id: binary_image
|
||||
file: ../../pnglogo.png
|
||||
type: BINARY
|
||||
dither: FloydSteinberg
|
||||
- id: transparent_transparent_image
|
||||
file: ../../pnglogo.png
|
||||
type: TRANSPARENT_BINARY
|
||||
- id: rgba_image
|
||||
file: ../../pnglogo.png
|
||||
type: RGBA
|
||||
resize: 50x50
|
||||
- id: rgb24_image
|
||||
file: ../../pnglogo.png
|
||||
type: RGB24
|
||||
use_transparency: yes
|
||||
- id: rgb565_image
|
||||
file: ../../pnglogo.png
|
||||
type: RGB565
|
||||
use_transparency: no
|
||||
- id: web_svg_image
|
||||
file: https://raw.githubusercontent.com/esphome/esphome-docs/a62d7ab193c1a464ed791670170c7d518189109b/images/logo.svg
|
||||
resize: 256x48
|
||||
type: TRANSPARENT_BINARY
|
||||
- id: web_tiff_image
|
||||
file: https://upload.wikimedia.org/wikipedia/commons/b/b6/SIPI_Jelly_Beans_4.1.07.tiff
|
||||
type: RGB24
|
||||
resize: 48x48
|
||||
- id: web_redirect_image
|
||||
file: https://avatars.githubusercontent.com/u/3060199?s=48&v=4
|
||||
type: RGB24
|
||||
resize: 48x48
|
||||
- id: mdi_alert
|
||||
file: mdi:alert-circle-outline
|
||||
resize: 50x50
|
||||
- id: another_alert_icon
|
||||
file: mdi:alert-outline
|
||||
type: BINARY
|
||||
<<: !include common.yaml
|
||||
|
@ -13,41 +13,4 @@ display:
|
||||
reset_pin: 21
|
||||
invert_colors: true
|
||||
|
||||
image:
|
||||
- id: binary_image
|
||||
file: ../../pnglogo.png
|
||||
type: BINARY
|
||||
dither: FloydSteinberg
|
||||
- id: transparent_transparent_image
|
||||
file: ../../pnglogo.png
|
||||
type: TRANSPARENT_BINARY
|
||||
- id: rgba_image
|
||||
file: ../../pnglogo.png
|
||||
type: RGBA
|
||||
resize: 50x50
|
||||
- id: rgb24_image
|
||||
file: ../../pnglogo.png
|
||||
type: RGB24
|
||||
use_transparency: yes
|
||||
- id: rgb565_image
|
||||
file: ../../pnglogo.png
|
||||
type: RGB565
|
||||
use_transparency: no
|
||||
- id: web_svg_image
|
||||
file: https://raw.githubusercontent.com/esphome/esphome-docs/a62d7ab193c1a464ed791670170c7d518189109b/images/logo.svg
|
||||
resize: 256x48
|
||||
type: TRANSPARENT_BINARY
|
||||
- id: web_tiff_image
|
||||
file: https://upload.wikimedia.org/wikipedia/commons/b/b6/SIPI_Jelly_Beans_4.1.07.tiff
|
||||
type: RGB24
|
||||
resize: 48x48
|
||||
- id: web_redirect_image
|
||||
file: https://avatars.githubusercontent.com/u/3060199?s=48&v=4
|
||||
type: RGB24
|
||||
resize: 48x48
|
||||
- id: mdi_alert
|
||||
file: mdi:alert-circle-outline
|
||||
resize: 50x50
|
||||
- id: another_alert_icon
|
||||
file: mdi:alert-outline
|
||||
type: BINARY
|
||||
<<: !include common.yaml
|
||||
|
@ -13,41 +13,4 @@ display:
|
||||
reset_pin: 16
|
||||
invert_colors: true
|
||||
|
||||
image:
|
||||
- id: binary_image
|
||||
file: ../../pnglogo.png
|
||||
type: BINARY
|
||||
dither: FloydSteinberg
|
||||
- id: transparent_transparent_image
|
||||
file: ../../pnglogo.png
|
||||
type: TRANSPARENT_BINARY
|
||||
- id: rgba_image
|
||||
file: ../../pnglogo.png
|
||||
type: RGBA
|
||||
resize: 50x50
|
||||
- id: rgb24_image
|
||||
file: ../../pnglogo.png
|
||||
type: RGB24
|
||||
use_transparency: yes
|
||||
- id: rgb565_image
|
||||
file: ../../pnglogo.png
|
||||
type: RGB565
|
||||
use_transparency: no
|
||||
- id: web_svg_image
|
||||
file: https://raw.githubusercontent.com/esphome/esphome-docs/a62d7ab193c1a464ed791670170c7d518189109b/images/logo.svg
|
||||
resize: 256x48
|
||||
type: TRANSPARENT_BINARY
|
||||
- id: web_tiff_image
|
||||
file: https://upload.wikimedia.org/wikipedia/commons/b/b6/SIPI_Jelly_Beans_4.1.07.tiff
|
||||
type: RGB24
|
||||
resize: 48x48
|
||||
- id: web_redirect_image
|
||||
file: https://avatars.githubusercontent.com/u/3060199?s=48&v=4
|
||||
type: RGB24
|
||||
resize: 48x48
|
||||
- id: mdi_alert
|
||||
file: mdi:alert-circle-outline
|
||||
resize: 50x50
|
||||
- id: another_alert_icon
|
||||
file: mdi:alert-outline
|
||||
type: BINARY
|
||||
<<: !include common.yaml
|
||||
|
8
tests/components/image/test.host.yaml
Normal file
8
tests/components/image/test.host.yaml
Normal file
@ -0,0 +1,8 @@
|
||||
display:
|
||||
- platform: sdl
|
||||
auto_clear_enabled: false
|
||||
dimensions:
|
||||
width: 480
|
||||
height: 480
|
||||
|
||||
<<: !include common.yaml
|
@ -13,41 +13,4 @@ display:
|
||||
reset_pin: 22
|
||||
invert_colors: true
|
||||
|
||||
image:
|
||||
- id: binary_image
|
||||
file: ../../pnglogo.png
|
||||
type: BINARY
|
||||
dither: FloydSteinberg
|
||||
- id: transparent_transparent_image
|
||||
file: ../../pnglogo.png
|
||||
type: TRANSPARENT_BINARY
|
||||
- id: rgba_image
|
||||
file: ../../pnglogo.png
|
||||
type: RGBA
|
||||
resize: 50x50
|
||||
- id: rgb24_image
|
||||
file: ../../pnglogo.png
|
||||
type: RGB24
|
||||
use_transparency: yes
|
||||
- id: rgb565_image
|
||||
file: ../../pnglogo.png
|
||||
type: RGB565
|
||||
use_transparency: no
|
||||
- id: web_svg_image
|
||||
file: https://raw.githubusercontent.com/esphome/esphome-docs/a62d7ab193c1a464ed791670170c7d518189109b/images/logo.svg
|
||||
resize: 256x48
|
||||
type: TRANSPARENT_BINARY
|
||||
- id: web_tiff_image
|
||||
file: https://upload.wikimedia.org/wikipedia/commons/b/b6/SIPI_Jelly_Beans_4.1.07.tiff
|
||||
type: RGB24
|
||||
resize: 48x48
|
||||
- id: web_redirect_image
|
||||
file: https://avatars.githubusercontent.com/u/3060199?s=48&v=4
|
||||
type: RGB24
|
||||
resize: 48x48
|
||||
- id: mdi_alert
|
||||
file: mdi:alert-circle-outline
|
||||
resize: 50x50
|
||||
- id: another_alert_icon
|
||||
file: mdi:alert-outline
|
||||
type: BINARY
|
||||
<<: !include common.yaml
|
||||
|
Loading…
Reference in New Issue
Block a user