From ea85c99a01684629f7b8b49722d466dfda04f4f9 Mon Sep 17 00:00:00 2001 From: Lucas CHOLLET Date: Fri, 11 Aug 2023 13:16:43 -0400 Subject: [PATCH] LibGfx/JPEGXL: Add support for cropped images Due to the way JPEG XL encodes its lossless images, it is sometimes interesting to embed a large image and crop the result at the end. This patch adds the functionality to crop a frame. Note that JPEG XL supports image composition (almost like layers in image editing software programs) and I tried to make these changes be a step toward image composing. It's a small step as we are still unable to read multiple frames, and we only support the `kReplace` blending mode. --- .../LibGfx/ImageFormats/JPEGXLLoader.cpp | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibGfx/ImageFormats/JPEGXLLoader.cpp b/Userland/Libraries/LibGfx/ImageFormats/JPEGXLLoader.cpp index b6f406a305..72883e87c6 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/JPEGXLLoader.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/JPEGXLLoader.cpp @@ -1681,6 +1681,37 @@ public: return image; } + void blend_into(Image& image, FrameHeader const& frame_header) const + { + // FIXME: We should use ec_blending_info when appropriate + + if (frame_header.blending_info.mode != BlendingInfo::BlendMode::kReplace) + TODO(); + + for (u16 i = 0; i < m_channels.size(); ++i) { + auto const& input_channel = m_channels[i]; + auto& output_channel = image.channels()[i]; + + for (u32 y = 0; y < input_channel.height(); ++y) { + auto const corrected_y = static_cast(y) + frame_header.y0; + if (corrected_y < 0) + continue; + if (corrected_y >= output_channel.height()) + break; + + for (u32 x = 0; x < input_channel.width(); ++x) { + auto const corrected_x = static_cast(x) + frame_header.x0; + if (corrected_x < 0) + continue; + if (corrected_x >= output_channel.width()) + break; + + output_channel.set(corrected_x, corrected_y, input_channel.get(x, y)); + } + } + }; + } + ErrorOr> to_bitmap(ImageMetadata& metadata) const { // FIXME: which channel size should we use? @@ -2560,7 +2591,10 @@ public: TRY(render_extra_channels(frame.image, m_metadata)); - m_bitmap = TRY(frame.image.to_bitmap(m_metadata)); + if (!m_image.has_value()) + m_image = TRY(Image::create({ m_header.width, m_header.height }, m_metadata)); + + frame.image.blend_into(*m_image, frame.frame_header); return {}; } @@ -2580,6 +2614,9 @@ public: TRY(decode_frame()); + m_bitmap = TRY(m_image->to_bitmap(m_metadata)); + m_image.clear(); + return {}; }(); @@ -2616,6 +2653,10 @@ private: LittleEndianInputBitStream m_stream; RefPtr m_bitmap; + // JPEG XL images can be composed of multiples sub-images, this variable is an internal + // representation of this blending before the final rendering (in m_bitmap) + Optional m_image; + Optional m_entropy_decoder {}; SizeHeader m_header;