diff --git a/esphome/components/online_image/image_decoder.cpp b/esphome/components/online_image/image_decoder.cpp index d8c0cc33c4..0ab7dadde3 100644 --- a/esphome/components/online_image/image_decoder.cpp +++ b/esphome/components/online_image/image_decoder.cpp @@ -9,10 +9,10 @@ namespace online_image { static const char *const TAG = "online_image.decoder"; bool ImageDecoder::set_size(int width, int height) { - bool resized = this->image_->resize_(width, height); + bool success = this->image_->resize_(width, height) > 0; this->x_scale_ = static_cast(this->image_->buffer_width_) / width; this->y_scale_ = static_cast(this->image_->buffer_height_) / height; - return resized; + return success; } void ImageDecoder::draw(int x, int y, int w, int h, const Color &color) { @@ -51,8 +51,9 @@ size_t DownloadBuffer::read(size_t len) { } size_t DownloadBuffer::resize(size_t size) { - if (this->size_ == size) { - return size; + if (this->size_ >= size) { + // Avoid useless reallocations; if the buffer is big enough, don't reallocate. + return this->size_; } this->allocator_.deallocate(this->buffer_, this->size_); this->buffer_ = this->allocator_.allocate(size); @@ -61,6 +62,8 @@ size_t DownloadBuffer::resize(size_t size) { this->size_ = size; return size; } else { + ESP_LOGE(TAG, "allocation of %zu bytes failed. Biggest block in heap: %zu Bytes", size, + this->allocator_.get_max_free_block_size()); this->size_ = 0; return 0; } diff --git a/esphome/components/online_image/jpeg_image.cpp b/esphome/components/online_image/jpeg_image.cpp index 0aff576da8..e5ee3dd8bf 100644 --- a/esphome/components/online_image/jpeg_image.cpp +++ b/esphome/components/online_image/jpeg_image.cpp @@ -58,7 +58,7 @@ int HOT JpegDecoder::decode(uint8_t *buffer, size_t size) { } if (!this->jpeg_.openRAM(buffer, size, draw_callback)) { - ESP_LOGE(TAG, "Could not open image for decoding."); + ESP_LOGE(TAG, "Could not open image for decoding: %d", this->jpeg_.getLastError()); return DECODE_ERROR_INVALID_TYPE; } auto jpeg_type = this->jpeg_.getJPEGType(); @@ -73,7 +73,9 @@ int HOT JpegDecoder::decode(uint8_t *buffer, size_t size) { this->jpeg_.setUserPointer(this); this->jpeg_.setPixelType(RGB8888); - this->set_size(this->jpeg_.getWidth(), this->jpeg_.getHeight()); + if (!this->set_size(this->jpeg_.getWidth(), this->jpeg_.getHeight())) { + return DECODE_ERROR_OUT_OF_MEMORY; + } if (!this->jpeg_.decode(0, 0, 0)) { ESP_LOGE(TAG, "Error while decoding."); this->jpeg_.close(); diff --git a/esphome/components/online_image/online_image.cpp b/esphome/components/online_image/online_image.cpp index 3b3d00a044..3411018901 100644 --- a/esphome/components/online_image/online_image.cpp +++ b/esphome/components/online_image/online_image.cpp @@ -64,33 +64,34 @@ void OnlineImage::release() { } } -bool OnlineImage::resize_(int width_in, int height_in) { +size_t OnlineImage::resize_(int width_in, int height_in) { int width = this->fixed_width_; int height = this->fixed_height_; - if (this->auto_resize_()) { + if (this->is_auto_resize_()) { width = width_in; height = height_in; if (this->width_ != width && this->height_ != height) { this->release(); } } - if (this->buffer_) { - return false; - } size_t new_size = this->get_buffer_size_(width, height); + if (this->buffer_) { + // Buffer already allocated => no need to resize + return new_size; + } ESP_LOGD(TAG, "Allocating new buffer of %zu bytes", new_size); this->buffer_ = this->allocator_.allocate(new_size); if (this->buffer_ == nullptr) { ESP_LOGE(TAG, "allocation of %zu bytes failed. Biggest block in heap: %zu Bytes", new_size, this->allocator_.get_max_free_block_size()); this->end_connection_(); - return false; + return 0; } this->buffer_width_ = width; this->buffer_height_ = height; this->width_ = width; ESP_LOGV(TAG, "New size: (%d, %d)", width, height); - return true; + return new_size; } void OnlineImage::update() { diff --git a/esphome/components/online_image/online_image.h b/esphome/components/online_image/online_image.h index 4abc047083..2d10e528b1 100644 --- a/esphome/components/online_image/online_image.h +++ b/esphome/components/online_image/online_image.h @@ -99,9 +99,22 @@ class OnlineImage : public PollingComponent, 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; } + ESPHOME_ALWAYS_INLINE bool is_auto_resize_() const { return this->fixed_width_ == 0 || this->fixed_height_ == 0; } - bool resize_(int width, int height); + /** + * @brief Resize the image buffer to the requested dimensions. + * + * The buffer will be allocated if not existing. + * If the dimensions have been fixed in the yaml config, the buffer will be created + * with those dimensions and not resized, even on request. + * Otherwise, the old buffer will be deallocated and a new buffer with the requested + * allocated + * + * @param width + * @param height + * @return 0 if no memory could be allocated, the size of the new buffer otherwise. + */ + size_t resize_(int width, int height); /** * @brief Draw a pixel into the buffer.