mirror of
https://github.com/esphome/esphome.git
synced 2025-01-26 22:21:58 +01:00
[online_image] Add binary bmp support (#8116)
Co-authored-by: guillempages <guillempages@users.noreply.github.com>
This commit is contained in:
parent
dee1d84979
commit
7fccc9ff86
@ -61,8 +61,22 @@ class PNGFormat(Format):
|
||||
cg.add_library("pngle", "1.0.2")
|
||||
|
||||
|
||||
class BMPFormat(Format):
|
||||
def __init__(self):
|
||||
super().__init__("BMP")
|
||||
|
||||
def actions(self):
|
||||
cg.add_define("USE_ONLINE_IMAGE_BMP_SUPPORT")
|
||||
|
||||
|
||||
# New formats can be added here.
|
||||
IMAGE_FORMATS = {x.image_type: x for x in (PNGFormat(),)}
|
||||
IMAGE_FORMATS = {
|
||||
x.image_type: x
|
||||
for x in (
|
||||
PNGFormat(),
|
||||
BMPFormat(),
|
||||
)
|
||||
}
|
||||
|
||||
OnlineImage = online_image_ns.class_("OnlineImage", cg.PollingComponent, Image_)
|
||||
|
||||
|
101
esphome/components/online_image/bmp_image.cpp
Normal file
101
esphome/components/online_image/bmp_image.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
#include "bmp_image.h"
|
||||
|
||||
#ifdef USE_ONLINE_IMAGE_BMP_SUPPORT
|
||||
|
||||
#include "esphome/components/display/display.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace online_image {
|
||||
|
||||
static const char *const TAG = "online_image.bmp";
|
||||
|
||||
int HOT BmpDecoder::decode(uint8_t *buffer, size_t size) {
|
||||
size_t index = 0;
|
||||
if (this->current_index_ == 0 && index == 0 && size > 14) {
|
||||
/**
|
||||
* BMP file format:
|
||||
* 0-1: Signature (BM)
|
||||
* 2-5: File size
|
||||
* 6-9: Reserved
|
||||
* 10-13: Pixel data offset
|
||||
*
|
||||
* Integer values are stored in little-endian format.
|
||||
*/
|
||||
|
||||
// Check if the file is a BMP image
|
||||
if (buffer[0] != 'B' || buffer[1] != 'M') {
|
||||
ESP_LOGE(TAG, "Not a BMP file");
|
||||
return DECODE_ERROR_INVALID_TYPE;
|
||||
}
|
||||
|
||||
this->download_size_ = encode_uint32(buffer[5], buffer[4], buffer[3], buffer[2]);
|
||||
this->data_offset_ = encode_uint32(buffer[13], buffer[12], buffer[11], buffer[10]);
|
||||
|
||||
this->current_index_ = 14;
|
||||
index = 14;
|
||||
}
|
||||
if (this->current_index_ == 14 && index == 14 && size > this->data_offset_) {
|
||||
/**
|
||||
* BMP DIB header:
|
||||
* 14-17: DIB header size
|
||||
* 18-21: Image width
|
||||
* 22-25: Image height
|
||||
* 26-27: Number of color planes
|
||||
* 28-29: Bits per pixel
|
||||
* 30-33: Compression method
|
||||
* 34-37: Image data size
|
||||
* 38-41: Horizontal resolution
|
||||
* 42-45: Vertical resolution
|
||||
* 46-49: Number of colors in the color table
|
||||
*/
|
||||
|
||||
this->width_ = encode_uint32(buffer[21], buffer[20], buffer[19], buffer[18]);
|
||||
this->height_ = encode_uint32(buffer[25], buffer[24], buffer[23], buffer[22]);
|
||||
this->bits_per_pixel_ = encode_uint16(buffer[29], buffer[28]);
|
||||
this->compression_method_ = encode_uint32(buffer[33], buffer[32], buffer[31], buffer[30]);
|
||||
this->image_data_size_ = encode_uint32(buffer[37], buffer[36], buffer[35], buffer[34]);
|
||||
this->color_table_entries_ = encode_uint32(buffer[49], buffer[48], buffer[47], buffer[46]);
|
||||
|
||||
switch (this->bits_per_pixel_) {
|
||||
case 1:
|
||||
this->width_bytes_ = (this->width_ % 8 == 0) ? (this->width_ / 8) : (this->width_ / 8 + 1);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Unsupported bits per pixel: %d", this->bits_per_pixel_);
|
||||
return DECODE_ERROR_UNSUPPORTED_FORMAT;
|
||||
}
|
||||
|
||||
if (this->compression_method_ != 0) {
|
||||
ESP_LOGE(TAG, "Unsupported compression method: %d", this->compression_method_);
|
||||
return DECODE_ERROR_UNSUPPORTED_FORMAT;
|
||||
}
|
||||
|
||||
if (!this->set_size(this->width_, this->height_)) {
|
||||
return DECODE_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
this->current_index_ = this->data_offset_;
|
||||
index = this->data_offset_;
|
||||
}
|
||||
while (index < size) {
|
||||
size_t paint_index = this->current_index_ - this->data_offset_;
|
||||
|
||||
uint8_t current_byte = buffer[index];
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
size_t x = (paint_index * 8) % this->width_ + i;
|
||||
size_t y = (this->height_ - 1) - (paint_index / this->width_bytes_);
|
||||
Color c = (current_byte & (1 << (7 - i))) ? display::COLOR_ON : display::COLOR_OFF;
|
||||
this->draw(x, y, 1, 1, c);
|
||||
}
|
||||
this->current_index_++;
|
||||
index++;
|
||||
}
|
||||
this->decoded_bytes_ += size;
|
||||
return size;
|
||||
};
|
||||
|
||||
} // namespace online_image
|
||||
} // namespace esphome
|
||||
|
||||
#endif // USE_ONLINE_IMAGE_BMP_SUPPORT
|
40
esphome/components/online_image/bmp_image.h
Normal file
40
esphome/components/online_image/bmp_image.h
Normal file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
#ifdef USE_ONLINE_IMAGE_BMP_SUPPORT
|
||||
|
||||
#include "image_decoder.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace online_image {
|
||||
|
||||
/**
|
||||
* @brief Image decoder specialization for PNG images.
|
||||
*/
|
||||
class BmpDecoder : public ImageDecoder {
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new BMP Decoder object.
|
||||
*
|
||||
* @param display The image to decode the stream into.
|
||||
*/
|
||||
BmpDecoder(OnlineImage *image) : ImageDecoder(image) {}
|
||||
|
||||
int HOT decode(uint8_t *buffer, size_t size) override;
|
||||
|
||||
protected:
|
||||
size_t current_index_{0};
|
||||
ssize_t width_{0};
|
||||
ssize_t height_{0};
|
||||
uint16_t bits_per_pixel_{0};
|
||||
uint32_t compression_method_{0};
|
||||
uint32_t image_data_size_{0};
|
||||
uint32_t color_table_entries_{0};
|
||||
size_t width_bytes_{0};
|
||||
size_t data_offset_{0};
|
||||
};
|
||||
|
||||
} // namespace online_image
|
||||
} // namespace esphome
|
||||
|
||||
#endif // USE_ONLINE_IMAGE_BMP_SUPPORT
|
@ -8,10 +8,11 @@ namespace online_image {
|
||||
|
||||
static const char *const TAG = "online_image.decoder";
|
||||
|
||||
void ImageDecoder::set_size(int width, int height) {
|
||||
this->image_->resize_(width, height);
|
||||
bool ImageDecoder::set_size(int width, int height) {
|
||||
bool resized = this->image_->resize_(width, height);
|
||||
this->x_scale_ = static_cast<double>(this->image_->buffer_width_) / width;
|
||||
this->y_scale_ = static_cast<double>(this->image_->buffer_height_) / height;
|
||||
return resized;
|
||||
}
|
||||
|
||||
void ImageDecoder::draw(int x, int y, int w, int h, const Color &color) {
|
||||
|
@ -4,6 +4,12 @@
|
||||
namespace esphome {
|
||||
namespace online_image {
|
||||
|
||||
enum DecodeError : int {
|
||||
DECODE_ERROR_INVALID_TYPE = -1,
|
||||
DECODE_ERROR_UNSUPPORTED_FORMAT = -2,
|
||||
DECODE_ERROR_OUT_OF_MEMORY = -3,
|
||||
};
|
||||
|
||||
class OnlineImage;
|
||||
|
||||
/**
|
||||
@ -45,8 +51,9 @@ class ImageDecoder {
|
||||
*
|
||||
* @param width The image's width.
|
||||
* @param height The image's height.
|
||||
* @return true if the image was resized, false otherwise.
|
||||
*/
|
||||
void set_size(int width, int height);
|
||||
bool set_size(int width, int height);
|
||||
|
||||
/**
|
||||
* @brief Fill a rectangle on the display_buffer using the defined color.
|
||||
|
@ -10,6 +10,10 @@ static const char *const TAG = "online_image";
|
||||
#include "png_image.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_ONLINE_IMAGE_BMP_SUPPORT
|
||||
#include "bmp_image.h"
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace online_image {
|
||||
|
||||
@ -120,9 +124,14 @@ void OnlineImage::update() {
|
||||
|
||||
#ifdef USE_ONLINE_IMAGE_PNG_SUPPORT
|
||||
if (this->format_ == ImageFormat::PNG) {
|
||||
this->decoder_ = esphome::make_unique<PngDecoder>(this);
|
||||
this->decoder_ = make_unique<PngDecoder>(this);
|
||||
}
|
||||
#endif // ONLINE_IMAGE_PNG_SUPPORT
|
||||
#ifdef USE_ONLINE_IMAGE_BMP_SUPPORT
|
||||
if (this->format_ == ImageFormat::BMP) {
|
||||
this->decoder_ = make_unique<BmpDecoder>(this);
|
||||
}
|
||||
#endif // ONLINE_IMAGE_BMP_SUPPORT
|
||||
|
||||
if (!this->decoder_) {
|
||||
ESP_LOGE(TAG, "Could not instantiate decoder. Image format unsupported.");
|
||||
|
@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/components/http_request/http_request.h"
|
||||
#include "esphome/components/image/image.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/components/http_request/http_request.h"
|
||||
#include "esphome/components/image/image.h"
|
||||
|
||||
#include "image_decoder.h"
|
||||
|
||||
@ -27,6 +27,8 @@ enum ImageFormat {
|
||||
JPEG,
|
||||
/** PNG format. */
|
||||
PNG,
|
||||
/** BMP format. */
|
||||
BMP,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -146,7 +148,7 @@ class OnlineImage : public PollingComponent,
|
||||
*/
|
||||
int buffer_height_;
|
||||
|
||||
friend void ImageDecoder::set_size(int width, int height);
|
||||
friend bool ImageDecoder::set_size(int width, int height);
|
||||
friend void ImageDecoder::draw(int x, int y, int w, int h, const Color &color);
|
||||
};
|
||||
|
||||
|
@ -60,6 +60,7 @@
|
||||
#define USE_NETWORK
|
||||
#define USE_NEXTION_TFT_UPLOAD
|
||||
#define USE_NUMBER
|
||||
#define USE_ONLINE_IMAGE_BMP_SUPPORT
|
||||
#define USE_ONLINE_IMAGE_PNG_SUPPORT
|
||||
#define USE_OTA
|
||||
#define USE_OTA_PASSWORD
|
||||
|
@ -26,6 +26,10 @@ online_image:
|
||||
format: PNG
|
||||
type: RGB
|
||||
transparency: chroma_key
|
||||
- id: online_binary_bmp
|
||||
url: https://samples-files.com/samples/images/bmp/480-360-sample.bmp
|
||||
format: BMP
|
||||
type: BINARY
|
||||
|
||||
# Check the set_url action
|
||||
esphome:
|
||||
|
Loading…
Reference in New Issue
Block a user