display: add BaseImage and provide only Image::get_pixel method (#4932)

This commit is contained in:
Kamil Trzciński 2023-06-15 01:15:46 +02:00 committed by GitHub
parent cef659b0de
commit 0411d52420
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 101 additions and 84 deletions

View file

@ -325,63 +325,8 @@ void DisplayBuffer::vprintf_(int x, int y, Font *font, Color color, TextAlign al
this->print(x, y, font, color, align, buffer);
}
void DisplayBuffer::image(int x, int y, Image *image, Color color_on, Color color_off) {
bool transparent = image->has_transparency();
switch (image->get_type()) {
case IMAGE_TYPE_BINARY: {
for (int img_x = 0; img_x < image->get_width(); img_x++) {
for (int img_y = 0; img_y < image->get_height(); img_y++) {
if (image->get_pixel(img_x, img_y)) {
this->draw_pixel_at(x + img_x, y + img_y, color_on);
} else if (!transparent) {
this->draw_pixel_at(x + img_x, y + img_y, color_off);
}
}
}
break;
}
case IMAGE_TYPE_GRAYSCALE:
for (int img_x = 0; img_x < image->get_width(); img_x++) {
for (int img_y = 0; img_y < image->get_height(); img_y++) {
auto color = image->get_grayscale_pixel(img_x, img_y);
if (color.w >= 0x80) {
this->draw_pixel_at(x + img_x, y + img_y, color);
}
}
}
break;
case IMAGE_TYPE_RGB565:
for (int img_x = 0; img_x < image->get_width(); img_x++) {
for (int img_y = 0; img_y < image->get_height(); img_y++) {
auto color = image->get_rgb565_pixel(img_x, img_y);
if (color.w >= 0x80) {
this->draw_pixel_at(x + img_x, y + img_y, color);
}
}
}
break;
case IMAGE_TYPE_RGB24:
for (int img_x = 0; img_x < image->get_width(); img_x++) {
for (int img_y = 0; img_y < image->get_height(); img_y++) {
auto color = image->get_color_pixel(img_x, img_y);
if (color.w >= 0x80) {
this->draw_pixel_at(x + img_x, y + img_y, color);
}
}
}
break;
case IMAGE_TYPE_RGBA:
for (int img_x = 0; img_x < image->get_width(); img_x++) {
for (int img_y = 0; img_y < image->get_height(); img_y++) {
auto color = image->get_rgba_pixel(img_x, img_y);
if (color.w >= 0x80) {
this->draw_pixel_at(x + img_x, y + img_y, color);
}
}
}
break;
}
void DisplayBuffer::image(int x, int y, BaseImage *image, Color color_on, Color color_off) {
image->draw(x, y, this, color_on, color_off);
}
#ifdef USE_GRAPH
@ -656,23 +601,91 @@ Font::Font(const GlyphData *data, int data_nr, int baseline, int height) : basel
glyphs_.emplace_back(&data[i]);
}
bool Image::get_pixel(int x, int y) const {
void Image::draw(int x, int y, DisplayBuffer *display, Color color_on, Color color_off) {
switch (type_) {
case IMAGE_TYPE_BINARY: {
for (int img_x = 0; img_x < width_; img_x++) {
for (int img_y = 0; img_y < height_; img_y++) {
if (this->get_binary_pixel_(img_x, img_y)) {
display->draw_pixel_at(x + img_x, y + img_y, color_on);
} else if (!this->transparent_) {
display->draw_pixel_at(x + img_x, y + img_y, color_off);
}
}
}
break;
}
case IMAGE_TYPE_GRAYSCALE:
for (int img_x = 0; img_x < width_; img_x++) {
for (int img_y = 0; img_y < height_; img_y++) {
auto color = this->get_grayscale_pixel_(img_x, img_y);
if (color.w >= 0x80) {
display->draw_pixel_at(x + img_x, y + img_y, color);
}
}
}
break;
case IMAGE_TYPE_RGB565:
for (int img_x = 0; img_x < width_; img_x++) {
for (int img_y = 0; img_y < height_; img_y++) {
auto color = this->get_rgb565_pixel_(img_x, img_y);
if (color.w >= 0x80) {
display->draw_pixel_at(x + img_x, y + img_y, color);
}
}
}
break;
case IMAGE_TYPE_RGB24:
for (int img_x = 0; img_x < width_; img_x++) {
for (int img_y = 0; img_y < height_; img_y++) {
auto color = this->get_rgb24_pixel_(img_x, img_y);
if (color.w >= 0x80) {
display->draw_pixel_at(x + img_x, y + img_y, color);
}
}
}
break;
case IMAGE_TYPE_RGBA:
for (int img_x = 0; img_x < width_; img_x++) {
for (int img_y = 0; img_y < height_; img_y++) {
auto color = this->get_rgba_pixel_(img_x, img_y);
if (color.w >= 0x80) {
display->draw_pixel_at(x + img_x, y + img_y, color);
}
}
}
break;
}
}
Color Image::get_pixel(int x, int y, Color color_on, Color color_off) const {
if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
return false;
return color_off;
switch (this->type_) {
case IMAGE_TYPE_BINARY:
return this->get_binary_pixel_(x, y) ? color_on : color_off;
case IMAGE_TYPE_GRAYSCALE:
return this->get_grayscale_pixel_(x, y);
case IMAGE_TYPE_RGB565:
return this->get_rgb565_pixel_(x, y);
case IMAGE_TYPE_RGB24:
return this->get_rgb24_pixel_(x, y);
case IMAGE_TYPE_RGBA:
return this->get_rgba_pixel_(x, y);
default:
return color_off;
}
}
bool Image::get_binary_pixel_(int x, int y) const {
const uint32_t width_8 = ((this->width_ + 7u) / 8u) * 8u;
const uint32_t pos = x + y * width_8;
return progmem_read_byte(this->data_start_ + (pos / 8u)) & (0x80 >> (pos % 8u));
}
Color Image::get_rgba_pixel(int x, int y) const {
if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
return Color::BLACK;
Color Image::get_rgba_pixel_(int x, int y) const {
const uint32_t pos = (x + y * this->width_) * 4;
return Color(progmem_read_byte(this->data_start_ + pos + 0), progmem_read_byte(this->data_start_ + pos + 1),
progmem_read_byte(this->data_start_ + pos + 2), progmem_read_byte(this->data_start_ + pos + 3));
}
Color Image::get_color_pixel(int x, int y) const {
if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
return Color::BLACK;
Color Image::get_rgb24_pixel_(int x, int y) const {
const uint32_t pos = (x + y * this->width_) * 3;
Color color = Color(progmem_read_byte(this->data_start_ + pos + 0), progmem_read_byte(this->data_start_ + pos + 1),
progmem_read_byte(this->data_start_ + pos + 2));
@ -685,9 +698,7 @@ Color Image::get_color_pixel(int x, int y) const {
}
return color;
}
Color Image::get_rgb565_pixel(int x, int y) const {
if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
return Color::BLACK;
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);
@ -703,9 +714,7 @@ Color Image::get_rgb565_pixel(int x, int y) const {
}
return color;
}
Color Image::get_grayscale_pixel(int x, int y) const {
if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
return Color::BLACK;
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);
uint8_t alpha = (gray == 1 && transparent_) ? 0 : 0xFF;
@ -716,7 +725,6 @@ int Image::get_height() const { return this->height_; }
ImageType Image::get_type() const { return this->type_; }
Image::Image(const uint8_t *data_start, int width, int height, ImageType type)
: width_(width), height_(height), type_(type), data_start_(data_start) {}
int Image::get_current_frame() const { return 0; }
Animation::Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, ImageType type)
: Image(data_start, width, height, type),

View file

@ -123,8 +123,8 @@ class Rect {
void info(const std::string &prefix = "rect info:");
};
class BaseImage;
class Font;
class Image;
class DisplayBuffer;
class DisplayPage;
class DisplayOnPageChangeTrigger;
@ -315,7 +315,7 @@ class DisplayBuffer {
* @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);
void image(int x, int y, BaseImage *image, Color color_on = COLOR_ON, Color color_off = COLOR_OFF);
#ifdef USE_GRAPH
/** Draw the `graph` with the top-left corner at [x,y] to the screen.
@ -529,24 +529,33 @@ class Font {
int height_;
};
class Image {
class BaseImage {
public:
virtual void draw(int x, int y, DisplayBuffer *display, Color color_on, Color color_off) = 0;
virtual int get_width() const = 0;
virtual int get_height() const = 0;
};
class Image : public BaseImage {
public:
Image(const uint8_t *data_start, int width, int height, ImageType type);
bool get_pixel(int x, int y) const;
Color get_color_pixel(int x, int y) const;
Color get_rgba_pixel(int x, int y) const;
Color get_rgb565_pixel(int x, int y) const;
Color get_grayscale_pixel(int x, int y) const;
int get_width() const;
int get_height() const;
Color get_pixel(int x, int y, Color color_on = COLOR_ON, Color color_off = COLOR_OFF) const;
int get_width() const override;
int get_height() const override;
ImageType get_type() const;
virtual int get_current_frame() const;
void draw(int x, int y, DisplayBuffer *display, Color color_on, Color color_off) override;
void set_transparency(bool transparent) { transparent_ = transparent; }
bool has_transparency() const { return transparent_; }
protected:
bool get_binary_pixel_(int x, int y) const;
Color get_rgb24_pixel_(int x, int y) const;
Color get_rgba_pixel_(int x, int y) const;
Color get_rgb565_pixel_(int x, int y) const;
Color get_grayscale_pixel_(int x, int y) const;
int width_;
int height_;
ImageType type_;
@ -559,7 +568,7 @@ class Animation : public Image {
Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, ImageType type);
uint32_t get_animation_frame_count() const;
int get_current_frame() const override;
int get_current_frame() const;
void next_frame();
void prev_frame();