5static const char *
const TAG =
"online_image";
6static const char *
const ETAG_HEADER_NAME =
"etag";
7static const char *
const IF_NONE_MATCH_HEADER_NAME =
"if-none-match";
8static const char *
const LAST_MODIFIED_HEADER_NAME =
"last-modified";
9static const char *
const IF_MODIFIED_SINCE_HEADER_NAME =
"if-modified-since";
13#ifdef USE_ONLINE_IMAGE_BMP_SUPPORT
16#ifdef USE_ONLINE_IMAGE_JPEG_SUPPORT
19#ifdef USE_ONLINE_IMAGE_PNG_SUPPORT
24namespace online_image {
34 return ((color.
r >> 2) + (color.
g >> 1) + (color.
b >> 2)) & 0x80;
39 : Image(nullptr, 0, 0,
type, transparency),
41 download_buffer_(download_buffer_size),
42 download_buffer_initial_size_(download_buffer_size),
45 fixed_height_(height),
46 is_big_endian_(is_big_endian) {
52 Image::draw(
x,
y, display, color_on, color_off);
60 ESP_LOGV(TAG,
"Deallocating old buffer");
89 ESP_LOGD(TAG,
"Allocating new buffer of %zu bytes", new_size);
92 ESP_LOGE(TAG,
"allocation of %zu bytes failed. Biggest block in heap: %zu Bytes", new_size,
100 ESP_LOGV(TAG,
"New size: (%d, %d)", width, height);
106 ESP_LOGW(TAG,
"Image already being updated.");
109 ESP_LOGI(TAG,
"Updating image %s", this->
url_.c_str());
111 std::list<http_request::Header> headers = {};
114 accept_header.
name =
"Accept";
115 std::string accept_mime_type;
117#ifdef USE_ONLINE_IMAGE_BMP_SUPPORT
119 accept_mime_type =
"image/bmp";
122#ifdef USE_ONLINE_IMAGE_JPEG_SUPPORT
124 accept_mime_type =
"image/jpeg";
127#ifdef USE_ONLINE_IMAGE_PNG_SUPPORT
129 accept_mime_type =
"image/png";
133 accept_mime_type =
"image/*";
135 accept_header.
value = accept_mime_type +
",*/*;q=0.8";
137 if (!this->
etag_.empty()) {
145 headers.push_back(accept_header);
154 ESP_LOGE(TAG,
"Download failed.");
161 if (http_code == HTTP_CODE_NOT_MODIFIED) {
163 ESP_LOGI(TAG,
"Server returned HTTP 304 (Not Modified). Download skipped.");
168 if (http_code != HTTP_CODE_OK) {
169 ESP_LOGE(TAG,
"HTTP result: %d", http_code);
175 ESP_LOGD(TAG,
"Starting download");
176 size_t total_size = this->
downloader_->content_length;
178#ifdef USE_ONLINE_IMAGE_BMP_SUPPORT
180 ESP_LOGD(TAG,
"Allocating BMP decoder");
181 this->
decoder_ = make_unique<BmpDecoder>(
this);
185#ifdef USE_ONLINE_IMAGE_JPEG_SUPPORT
187 ESP_LOGD(TAG,
"Allocating JPEG decoder");
188 this->
decoder_ = esphome::make_unique<JpegDecoder>(
this);
192#ifdef USE_ONLINE_IMAGE_PNG_SUPPORT
194 ESP_LOGD(TAG,
"Allocating PNG decoder");
195 this->
decoder_ = make_unique<PngDecoder>(
this);
201 ESP_LOGE(TAG,
"Could not instantiate decoder. Image format unsupported: %d", this->
format_);
206 auto prepare_result = this->
decoder_->prepare(total_size);
207 if (prepare_result < 0) {
212 ESP_LOGI(TAG,
"Downloading image (Size: %zu)", total_size);
226 ESP_LOGD(TAG,
"Image fully downloaded, read %zu bytes, width/height = %d/%d", this->
downloader_->get_bytes_read(),
227 this->width_, this->height_);
228 ESP_LOGD(TAG,
"Total time: %" PRIu32
"s", (uint32_t) (::time(
nullptr) - this->
start_time_));
236 ESP_LOGE(TAG,
"Downloader not instantiated; cannot download");
250 ESP_LOGE(TAG,
"Error when decoding image.");
262 if (color.
g == 1 && color.
r == 0 && color.
b == 0) {
265 if (color.
w < 0x80) {
275 ESP_LOGE(TAG,
"Buffer not allocated!");
279 ESP_LOGE(TAG,
"Tried to paint a pixel (%d,%d) outside the image!",
x,
y);
283 switch (this->
type_) {
285 const uint32_t width_8 = ((this->
width_ + 7u) / 8u) * 8u;
286 pos =
x +
y * width_8;
287 auto bitno = 0x80 >> (pos % 8u);
300 auto gray =
static_cast<uint8_t
>(0.2125 * color.
r + 0.7154 * color.
g + 0.0721 * color.
b);
305 if (color.
w < 0x80) {
319 this->
buffer_[pos + 0] =
static_cast<uint8_t
>((col565 >> 8) & 0xFF);
320 this->
buffer_[pos + 1] =
static_cast<uint8_t
>(col565 & 0xFF);
322 this->
buffer_[pos + 0] =
static_cast<uint8_t
>(col565 & 0xFF);
323 this->
buffer_[pos + 1] =
static_cast<uint8_t
>((col565 >> 8) & 0xFF);
353 if ((url.length() < 8) || !url.starts_with(
"http") || (url.find(
"://") == std::string::npos)) {
354 ESP_LOGE(TAG,
"URL is invalid and/or must be prefixed with 'http://' or 'https://'");
void enable_loop()
Enable this component's loop.
void disable_loop()
Disable this component's loop.
esphome::http_request::HttpRequestComponent * parent_
void deallocate(T *p, size_t n)
size_t get_max_free_block_size() const
Return the maximum size block this allocator could allocate.
static uint16_t color_to_565(Color color, ColorOrder color_order=ColorOrder::COLOR_ORDER_RGB)
std::shared_ptr< HttpContainer > get(const std::string &url)
const uint8_t * data_start_
bool has_transparency() const
Transparency transparency_
void draw(int x, int y, display::Display *display, Color color_on, Color color_off) override
size_t free_capacity() const
uint8_t * data(size_t offset=0)
std::string etag_
The value of the ETag HTTP header provided in the last response.
size_t resize_(int width, int height)
Resize the image buffer to the requested dimensions.
bool validate_url_(const std::string &url)
int get_position_(int x, int y) const
image::Image * placeholder_
const ImageFormat format_
uint32_t get_buffer_size_() const
void map_chroma_key(Color &color)
CallbackManager< void(bool)> download_finished_callback_
void draw_pixel_(int x, int y, Color color)
Draw a pixel into the buffer.
bool is_big_endian_
Whether the image is stored in big-endian format.
std::vector< std::pair< std::string, TemplatableValue< std::string > > > request_headers_
OnlineImage(const std::string &url, int width, int height, ImageFormat format, image::ImageType type, image::Transparency transparency, uint32_t buffer_size, bool is_big_endian)
Construct a new OnlineImage object.
friend void ImageDecoder::draw(int x, int y, int w, int h, const Color &color)
void add_on_error_callback(std::function< void()> &&callback)
std::unique_ptr< ImageDecoder > decoder_
RAMAllocator< uint8_t > allocator_
void add_on_finished_callback(std::function< void(bool)> &&callback)
int buffer_width_
Actual width of the current image.
ESPHOME_ALWAYS_INLINE bool is_auto_resize_() const
DownloadBuffer download_buffer_
void set_url(const std::string &url)
Set the URL to download the image from.
std::shared_ptr< http_request::HttpContainer > downloader_
const int fixed_width_
width requested on configuration, or 0 if non specified.
CallbackManager< void()> download_error_callback_
const int fixed_height_
height requested on configuration, or 0 if non specified.
int buffer_height_
Actual height of the current image.
size_t download_buffer_initial_size_
This is the initial size of the download buffer, not the current size.
std::string last_modified_
The value of the Last-Modified HTTP header provided in the last response.
void release()
Release the buffer storing the image.
@ TRANSPARENCY_ALPHA_CHANNEL
@ TRANSPARENCY_CHROMA_KEY
bool is_color_on(const Color &color)
ImageFormat
Format that the image is encoded with.
Providing packet encoding functions for exchanging data with a remote host.