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) {
51 Image::draw(
x,
y, display, color_on, color_off);
59 ESP_LOGV(TAG,
"Deallocating old buffer");
88 ESP_LOGD(TAG,
"Allocating new buffer of %zu bytes", new_size);
91 ESP_LOGE(TAG,
"allocation of %zu bytes failed. Biggest block in heap: %zu Bytes", new_size,
99 ESP_LOGV(TAG,
"New size: (%d, %d)", width, height);
105 ESP_LOGW(TAG,
"Image already being updated.");
108 ESP_LOGI(TAG,
"Updating image %s", this->
url_.c_str());
110 std::list<http_request::Header> headers = {};
113 accept_header.
name =
"Accept";
114 std::string accept_mime_type;
116#ifdef USE_ONLINE_IMAGE_BMP_SUPPORT
118 accept_mime_type =
"image/bmp";
121#ifdef USE_ONLINE_IMAGE_JPEG_SUPPORT
123 accept_mime_type =
"image/jpeg";
126#ifdef USE_ONLINE_IMAGE_PNG_SUPPORT
128 accept_mime_type =
"image/png";
132 accept_mime_type =
"image/*";
134 accept_header.
value = accept_mime_type +
",*/*;q=0.8";
136 if (!this->
etag_.empty()) {
144 headers.push_back(accept_header);
153 ESP_LOGE(TAG,
"Download failed.");
160 if (http_code == HTTP_CODE_NOT_MODIFIED) {
162 ESP_LOGI(TAG,
"Server returned HTTP 304 (Not Modified). Download skipped.");
167 if (http_code != HTTP_CODE_OK) {
168 ESP_LOGE(TAG,
"HTTP result: %d", http_code);
174 ESP_LOGD(TAG,
"Starting download");
175 size_t total_size = this->
downloader_->content_length;
177#ifdef USE_ONLINE_IMAGE_BMP_SUPPORT
179 ESP_LOGD(TAG,
"Allocating BMP decoder");
183#ifdef USE_ONLINE_IMAGE_JPEG_SUPPORT
185 ESP_LOGD(TAG,
"Allocating JPEG decoder");
189#ifdef USE_ONLINE_IMAGE_PNG_SUPPORT
191 ESP_LOGD(TAG,
"Allocating PNG decoder");
197 ESP_LOGE(TAG,
"Could not instantiate decoder. Image format unsupported: %d", this->
format_);
202 auto prepare_result = this->
decoder_->prepare(total_size);
203 if (prepare_result < 0) {
208 ESP_LOGI(TAG,
"Downloading image (Size: %zu)", total_size);
221 ESP_LOGD(TAG,
"Image fully downloaded, read %zu bytes, width/height = %d/%d", this->
downloader_->get_bytes_read(),
222 this->width_, this->height_);
223 ESP_LOGD(TAG,
"Total time: %lds", ::time(
nullptr) - this->
start_time_);
231 ESP_LOGE(TAG,
"Downloader not instantiated; cannot download");
245 ESP_LOGE(TAG,
"Error when decoding image.");
257 if (color.
g == 1 && color.
r == 0 && color.
b == 0) {
260 if (color.
w < 0x80) {
270 ESP_LOGE(TAG,
"Buffer not allocated!");
274 ESP_LOGE(TAG,
"Tried to paint a pixel (%d,%d) outside the image!",
x,
y);
278 switch (this->
type_) {
280 const uint32_t width_8 = ((this->
width_ + 7u) / 8u) * 8u;
281 pos =
x +
y * width_8;
282 auto bitno = 0x80 >> (pos % 8u);
295 uint8_t gray =
static_cast<uint8_t
>(0.2125 * color.
r + 0.7154 * color.
g + 0.0721 * color.
b);
300 if (color.
w < 0x80) {
313 this->
buffer_[pos + 0] =
static_cast<uint8_t
>((col565 >> 8) & 0xFF);
314 this->
buffer_[pos + 1] =
static_cast<uint8_t
>(col565 & 0xFF);
343 if ((url.length() < 8) || (url.find(
"http") != 0) || (url.find(
"://") == std::string::npos)) {
344 ESP_LOGE(TAG,
"URL is invalid and/or must be prefixed with 'http://' or 'https://'");
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.
std::vector< std::pair< std::string, TemplatableValue< std::string > > > request_headers_
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.
OnlineImage(const std::string &url, int width, int height, ImageFormat format, image::ImageType type, image::Transparency transparency, uint32_t buffer_size)
Construct a new OnlineImage object.
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.
std::unique_ptr< T > make_unique(Args &&...args)