diff options
author | Nico Weber <thakis@chromium.org> | 2023-02-24 22:32:14 -0500 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2023-02-25 16:02:51 +0100 |
commit | 0774d2135ca2a03181e1849f3b030b1e2dced986 (patch) | |
tree | 7d8d113e6f98e26aaa5806f6a759d72c62c14e1f | |
parent | e56e7db9d44e1ba13df743ffccabc33b628cee42 (diff) | |
download | serenity-0774d2135ca2a03181e1849f3b030b1e2dced986.zip |
LibGfx: Parse some of WebP 'VP8 ' chunk
This is for lossy compression, in which case a WebP file is
a single VP8 key frame.
This only parses the 10-byte frame header, which contains image
dimensions (and some other things).
For now, just dbgln_if() all data. Eventually we'll want to use at
least width and height.
-rw-r--r-- | Userland/Libraries/LibGfx/WebPLoader.cpp | 53 |
1 files changed, 50 insertions, 3 deletions
diff --git a/Userland/Libraries/LibGfx/WebPLoader.cpp b/Userland/Libraries/LibGfx/WebPLoader.cpp index 7a6b855b0f..d9e181fe4a 100644 --- a/Userland/Libraries/LibGfx/WebPLoader.cpp +++ b/Userland/Libraries/LibGfx/WebPLoader.cpp @@ -147,11 +147,58 @@ static ErrorOr<Chunk> decode_webp_advance_chunk(WebPLoadingContext& context, Rea } // https://developers.google.com/speed/webp/docs/riff_container#simple_file_format_lossy +// https://datatracker.ietf.org/doc/html/rfc6386#section-19 "Annex A: Bitstream Syntax" static ErrorOr<void> decode_webp_simple_lossy(WebPLoadingContext& context, Chunk const& vp8_chunk) { - // FIXME - (void)context; - (void)vp8_chunk; + VERIFY(vp8_chunk.type == FourCC("VP8 ")); + + if (vp8_chunk.data.size() < 10) + return context.error("WebPImageDecoderPlugin: 'VP8 ' chunk too small"); + + // FIXME: Eventually, this should probably call into LibVideo/VP8, + // and image decoders should move into LibImageDecoders which depends on both LibGfx and LibVideo. + // (LibVideo depends on LibGfx, so LibGfx can't depend on LibVideo itself.) + + // https://datatracker.ietf.org/doc/html/rfc6386#section-4 "Overview of Compressed Data Format" + // "The decoder is simply presented with a sequence of compressed frames [...] + // The first frame presented to the decompressor is [...] a key frame. [...] + // [E]very compressed frame has three or more pieces. It begins with an uncompressed data chunk comprising 10 bytes in the case of key frames + + u8 const* data = vp8_chunk.data.data(); + + // https://datatracker.ietf.org/doc/html/rfc6386#section-9.1 "Uncompressed Data Chunk" + u32 frame_tag = data[0] | (data[1] << 8) | (data[2] << 16); + bool is_key_frame = (frame_tag & 1) == 0; // https://www.rfc-editor.org/errata/eid5534 + u8 version = (frame_tag & 0xe) >> 1; + bool show_frame = (frame_tag & 0x10) != 0; + u32 size_of_first_partition = frame_tag >> 5; + + if (!is_key_frame) + return context.error("WebPImageDecoderPlugin: 'VP8 ' chunk not a key frame"); + + // FIXME: !show_frame does not make sense in a webp file either, probably? + + u32 start_code = data[3] | (data[4] << 8) | (data[5] << 16); + if (start_code != 0x2a019d) // https://www.rfc-editor.org/errata/eid7370 + return context.error("WebPImageDecoderPlugin: 'VP8 ' chunk invalid start_code"); + + // "The scaling specifications for each dimension are encoded as follows. + // 0 | No upscaling (the most common case). + // 1 | Upscale by 5/4. + // 2 | Upscale by 5/3. + // 3 | Upscale by 2." + // This is a display-time operation and doesn't affect decoding. + u16 width_and_horizontal_scale = data[6] | (data[7] << 8); + u16 width = width_and_horizontal_scale & 0x3fff; + u8 horizontal_scale = width_and_horizontal_scale >> 14; + + u16 heigth_and_vertical_scale = data[8] | (data[9] << 8); + u16 height = heigth_and_vertical_scale & 0x3fff; + u8 vertical_scale = heigth_and_vertical_scale >> 14; + + dbgln_if(WEBP_DEBUG, "version {}, show_frame {}, size_of_first_partition {}, width {}, horizontal_scale {}, height {}, vertical_scale {}", + version, show_frame, size_of_first_partition, width, horizontal_scale, height, vertical_scale); + return {}; } |