10#ifdef USE_RUNTIME_IMAGE_BMP
13#ifdef USE_RUNTIME_IMAGE_JPEG
16#ifdef USE_RUNTIME_IMAGE_PNG
22static const char *
const TAG =
"runtime_image";
25static constexpr int MAX_IMAGE_DIMENSION = 32767;
26static constexpr int MAX_IMAGE_BPP = 32;
27static_assert((
static_cast<uint64_t
>(MAX_IMAGE_BPP) * MAX_IMAGE_DIMENSION + 7) / 8 * MAX_IMAGE_DIMENSION <=
28 std::numeric_limits<size_t>::max(),
29 "MAX_IMAGE_DIMENSION must keep the worst-case buffer size within size_t");
37 return ((color.
r >> 2) + (color.
g >> 1) + (color.
b >> 2)) & 0x80;
41 image::Image *placeholder,
bool is_big_endian,
int fixed_width,
int fixed_height)
42 : Image(nullptr, 0, 0,
type, transparency),
44 fixed_width_(fixed_width),
45 fixed_height_(fixed_height),
46 placeholder_(placeholder),
47 is_big_endian_(is_big_endian) {}
60 target_width =
static_cast<int>(width * scale);
61 target_height =
static_cast<int>(height * scale);
76 ESP_LOGE(TAG,
"Buffer not allocated!");
80 ESP_LOGE(TAG,
"Tried to paint a pixel (%d,%d) outside the image!",
x,
y);
84 switch (this->
type_) {
88 auto bitno = 0x80 >> (
pos % 8u);
102 auto gray =
static_cast<uint8_t
>(0.2125 * color.
r + 0.7154 * color.
g + 0.0721 * color.
b);
107 if (color.
w < 0x80) {
119 Color mapped_color = color;
123 this->
buffer_[pos + 0] =
static_cast<uint8_t
>((rgb565 >> 8) & 0xFF);
124 this->
buffer_[pos + 1] =
static_cast<uint8_t
>(rgb565 & 0xFF);
126 this->
buffer_[pos + 0] =
static_cast<uint8_t
>(rgb565 & 0xFF);
127 this->
buffer_[pos + 1] =
static_cast<uint8_t
>((rgb565 >> 8) & 0xFF);
137 Color mapped_color = color;
139 this->
buffer_[pos + 0] = mapped_color.
b;
140 this->
buffer_[pos + 1] = mapped_color.
g;
141 this->
buffer_[pos + 2] = mapped_color.
r;
152 if (color.
g == 1 && color.
r == 0 && color.
b == 0) {
155 if (color.
w < 0x80) {
166 Image::draw(
x,
y, display, color_on, color_off);
176 ESP_LOGW(TAG,
"Decoding already in progress");
182 ESP_LOGE(TAG,
"Failed to create decoder for format %d", this->
format_);
190 int result = this->
decoder_->prepare(expected_size);
192 ESP_LOGE(TAG,
"Failed to prepare decoder: %d", result);
202 ESP_LOGE(TAG,
"No decoder initialized");
238 return this->
decoder_->is_finished();
261 memset(&this->
dsc_, 0,
sizeof(this->
dsc_));
270 ESP_LOGE(TAG,
"Refusing to allocate buffer for invalid image dimensions %dx%d", width, height);
284 ESP_LOGD(TAG,
"Allocating buffer: %dx%d, %zu bytes", width, height, new_size);
289 ESP_LOGE(TAG,
"Failed to allocate %zu bytes. Largest free block: %zu", new_size,
295 memset(this->
buffer_, 0, new_size);
305 if (width <= 0 || height <= 0 || width > MAX_IMAGE_DIMENSION || height > MAX_IMAGE_DIMENSION) {
310 return static_cast<size_t>(width) * height * 3;
312 return (
static_cast<size_t>(this->
get_bpp()) * width + 7u) / 8u * height;
319#ifdef USE_RUNTIME_IMAGE_BMP
321 return make_unique<BmpDecoder>(
this);
323#ifdef USE_RUNTIME_IMAGE_JPEG
325 return make_unique<JpegDecoder>(
this);
327#ifdef USE_RUNTIME_IMAGE_PNG
329 return make_unique<PngDecoder>(
this);
332 ESP_LOGE(TAG,
"Unsupported image format: %d", this->
format_);
An STL allocator that uses SPI or internal RAM.
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)
const uint8_t * data_start_
bool has_transparency() const
ImageType get_type() const
Transparency transparency_
void draw(int x, int y, display::Display *display, Color color_on, Color color_off) override
size_t get_buffer_size_(int width, int height) const
Get the buffer size in bytes for given dimensions.
bool is_big_endian_
Whether the image is stored in big-endian format.
void draw(int x, int y, display::Display *display, Color color_on, Color color_off) override
int buffer_width_
Actual width of the current image.
bool end_decode()
Complete the decoding process.
int get_position_(int x, int y) const
Get the position in the buffer for a pixel.
const int fixed_height_
Fixed height requested on configuration, or 0 if not specified.
void release_buffer_()
Release only the image buffer without resetting the decoder.
int resize(int width, int height)
Resize the image buffer to the requested dimensions.
int feed_data(uint8_t *data, size_t len)
Feed data to the decoder.
const int fixed_width_
Fixed width requested on configuration, or 0 if not specified.
bool is_decode_finished() const
Check if the decoder has finished processing all data.
void release()
Release the image buffer and free memory.
image::Image * placeholder_
Placeholder image to show when the runtime image is not available.
RuntimeImage(ImageFormat format, image::ImageType type, image::Transparency transparency, image::Image *placeholder=nullptr, bool is_big_endian=false, int fixed_width=0, int fixed_height=0)
Construct a new RuntimeImage object.
const ImageFormat format_
The image format this RuntimeImage is configured to decode.
size_t resize_buffer_(int width, int height)
Resize the image buffer to the requested dimensions.
std::unique_ptr< ImageDecoder > decoder_
bool progressive_display_
std::unique_ptr< ImageDecoder > create_decoder_()
Create decoder instance for the image's format.
void draw_pixel(int x, int y, const Color &color)
int buffer_height_
Actual height of the current image.
bool begin_decode(size_t expected_size=0)
Begin decoding an image.
void map_chroma_key(Color &color)
@ TRANSPARENCY_ALPHA_CHANNEL
@ TRANSPARENCY_CHROMA_KEY
bool is_color_on(const Color &color)
ImageFormat
Image format types that can be decoded dynamically.
const char int const __FlashStringHelper * format