瀏覽代碼

LibGfx/JPEGXL: Support images with the `have_crop` option in FrameHeader

This commit only allows us to read these values. The decoder will still
output the image as if no cropping was requested.
Lucas CHOLLET 1 年之前
父節點
當前提交
70e4d3a9b6
共有 1 個文件被更改,包括 29 次插入8 次删除
  1. 29 8
      Userland/Libraries/LibGfx/ImageFormats/JPEGXLLoader.cpp

+ 29 - 8
Userland/Libraries/LibGfx/ImageFormats/JPEGXLLoader.cpp

@@ -681,6 +681,10 @@ struct FrameHeader {
 
     u8 lf_level {};
     bool have_crop { false };
+    i32 x0 {};
+    i32 y0 {};
+    u32 width {};
+    u32 height {};
 
     BlendingInfo blending_info {};
     FixedArray<BlendingInfo> ec_blending_info {};
@@ -701,7 +705,9 @@ static int operator&(FrameHeader::Flags first, FrameHeader::Flags second)
     return static_cast<int>(first) & static_cast<int>(second);
 }
 
-static ErrorOr<FrameHeader> read_frame_header(LittleEndianInputBitStream& stream, ImageMetadata const& metadata)
+static ErrorOr<FrameHeader> read_frame_header(LittleEndianInputBitStream& stream,
+    SizeHeader size_header,
+    ImageMetadata const& metadata)
 {
     FrameHeader frame_header;
     bool const all_default = TRY(stream.read_bit());
@@ -744,15 +750,29 @@ static ErrorOr<FrameHeader> read_frame_header(LittleEndianInputBitStream& stream
         if (frame_header.frame_type != FrameHeader::FrameType::kLFFrame)
             frame_header.have_crop = TRY(stream.read_bit());
 
-        if (frame_header.have_crop)
-            TODO();
+        if (frame_header.have_crop) {
+            auto const read_crop_dimension = [&]() -> ErrorOr<u32> {
+                return U32(TRY(stream.read_bits(8)), 256 + TRY(stream.read_bits(11)), 2304 + TRY(stream.read_bits(14)), 18688 + TRY(stream.read_bits(30)));
+            };
+
+            if (frame_header.frame_type != FrameHeader::FrameType::kReferenceOnly) {
+                frame_header.x0 = unpack_signed(TRY(read_crop_dimension()));
+                frame_header.y0 = unpack_signed(TRY(read_crop_dimension()));
+            }
+
+            frame_header.width = TRY(read_crop_dimension());
+            frame_header.height = TRY(read_crop_dimension());
+        }
 
         bool const normal_frame = frame_header.frame_type == FrameHeader::FrameType::kRegularFrame
             || frame_header.frame_type == FrameHeader::FrameType::kSkipProgressive;
 
-        // FIXME: also consider "cropped" image of the dimension of the frame
-        VERIFY(!frame_header.have_crop);
-        bool const full_frame = !frame_header.have_crop;
+        // Let full_frame be true if and only if have_crop is false or if the frame area given
+        // by width and height and offsets x0 and y0 completely covers the image area.
+        bool const cover_image_area = frame_header.x0 <= 0 && frame_header.y0 <= 0
+            && (frame_header.width + frame_header.x0 >= size_header.width)
+            && (frame_header.height + frame_header.y0 == size_header.height);
+        bool const full_frame = !frame_header.have_crop || cover_image_area;
 
         if (normal_frame) {
             frame_header.blending_info = TRY(read_blending_info(stream, metadata, full_frame));
@@ -2304,13 +2324,14 @@ static ErrorOr<Frame> read_frame(LittleEndianInputBitStream& stream,
 
     Frame frame;
 
-    frame.frame_header = TRY(read_frame_header(stream, metadata));
+    frame.frame_header = TRY(read_frame_header(stream, size_header, metadata));
 
     if (!frame.frame_header.have_crop) {
         frame.width = size_header.width;
         frame.height = size_header.height;
     } else {
-        TODO();
+        frame.width = frame.frame_header.width;
+        frame.height = frame.frame_header.height;
     }
 
     if (frame.frame_header.upsampling > 1) {