Ver Fonte

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.
Lucas CHOLLET há 1 ano atrás
pai
commit
ea85c99a01
1 ficheiros alterados com 42 adições e 1 exclusões
  1. 42 1
      Userland/Libraries/LibGfx/ImageFormats/JPEGXLLoader.cpp

+ 42 - 1
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<i64>(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<i64>(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<NonnullRefPtr<Bitmap>> 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<Gfx::Bitmap> 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<Image> m_image;
+
     Optional<EntropyDecoder> m_entropy_decoder {};
 
     SizeHeader m_header;