summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNico Weber <thakis@chromium.org>2023-05-08 00:48:23 -0400
committerAndreas Kling <kling@serenityos.org>2023-05-09 06:35:56 +0200
commitbc207fd0a05fd50924082e0e92e8f91581d55772 (patch)
treecde67cb561df759db41f4605c95c084f4e9fe111
parent83da7ad875d8b0b5e09d8f6661a4ff7d708e07d6 (diff)
downloadserenity-bc207fd0a05fd50924082e0e92e8f91581d55772.zip
LibGfx/WebP: Move lossy decoder to its own file
Pure code move (except of removing `static` on the two public functions in the new header), not behavior change. There isn't a lot of lossy decoder yet, but it'll make implementing it more convenient. No behavior change.
-rw-r--r--Userland/Libraries/LibGfx/CMakeLists.txt1
-rw-r--r--Userland/Libraries/LibGfx/ImageFormats/WebPLoader.cpp82
-rw-r--r--Userland/Libraries/LibGfx/ImageFormats/WebPLoaderLossy.cpp87
-rw-r--r--Userland/Libraries/LibGfx/ImageFormats/WebPLoaderLossy.h31
4 files changed, 120 insertions, 81 deletions
diff --git a/Userland/Libraries/LibGfx/CMakeLists.txt b/Userland/Libraries/LibGfx/CMakeLists.txt
index 7af66dafa7..4e88d5f65f 100644
--- a/Userland/Libraries/LibGfx/CMakeLists.txt
+++ b/Userland/Libraries/LibGfx/CMakeLists.txt
@@ -49,6 +49,7 @@ set(SOURCES
ImageFormats/TGALoader.cpp
ImageFormats/WebPLoader.cpp
ImageFormats/WebPLoaderLossless.cpp
+ ImageFormats/WebPLoaderLossy.cpp
Painter.cpp
Palette.cpp
Path.cpp
diff --git a/Userland/Libraries/LibGfx/ImageFormats/WebPLoader.cpp b/Userland/Libraries/LibGfx/ImageFormats/WebPLoader.cpp
index b5cc00e55b..e5b9715d47 100644
--- a/Userland/Libraries/LibGfx/ImageFormats/WebPLoader.cpp
+++ b/Userland/Libraries/LibGfx/ImageFormats/WebPLoader.cpp
@@ -11,11 +11,11 @@
#include <AK/Vector.h>
#include <LibGfx/ImageFormats/WebPLoader.h>
#include <LibGfx/ImageFormats/WebPLoaderLossless.h>
+#include <LibGfx/ImageFormats/WebPLoaderLossy.h>
#include <LibGfx/Painter.h>
// Overview: https://developers.google.com/speed/webp/docs/compression
// Container: https://developers.google.com/speed/webp/docs/riff_container
-// Lossy format: https://datatracker.ietf.org/doc/html/rfc6386
namespace Gfx {
@@ -55,17 +55,6 @@ struct Chunk {
ReadonlyBytes data;
};
-struct VP8Header {
- u8 version;
- bool show_frame;
- u32 size_of_first_partition;
- u32 width;
- u8 horizontal_scale;
- u32 height;
- u8 vertical_scale;
- ReadonlyBytes lossy_data;
-};
-
struct VP8XHeader {
bool has_icc;
bool has_alpha;
@@ -228,75 +217,6 @@ static ErrorOr<Chunk> decode_webp_advance_chunk(ReadonlyBytes& chunks)
return chunk;
}
-// 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<VP8Header> decode_webp_chunk_VP8_header(ReadonlyBytes vp8_data)
-{
- if (vp8_data.size() < 10)
- return Error::from_string_literal("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_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 Error::from_string_literal("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 Error::from_string_literal("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 VP8Header { version, show_frame, size_of_first_partition, width, horizontal_scale, height, vertical_scale, vp8_data.slice(10) };
-}
-
-static ErrorOr<NonnullRefPtr<Bitmap>> decode_webp_chunk_VP8_contents(VP8Header const& vp8_header, bool include_alpha_channel)
-{
- auto bitmap_format = include_alpha_channel ? BitmapFormat::BGRA8888 : BitmapFormat::BGRx8888;
-
- // Uncomment this to test ALPH decoding for WebP-lossy-with-alpha images while lossy decoding isn't implemented yet.
-#if 0
- return Bitmap::create(bitmap_format, { vp8_header.width, vp8_header.height });
-#else
- // FIXME: Implement webp lossy decoding.
- (void)vp8_header;
- (void)bitmap_format;
- return Error::from_string_literal("WebPImageDecoderPlugin: decoding lossy webps not yet implemented");
-#endif
-}
-
// https://developers.google.com/speed/webp/docs/riff_container#alpha
static ErrorOr<void> decode_webp_chunk_ALPH(Chunk const& alph_chunk, Bitmap& bitmap)
{
diff --git a/Userland/Libraries/LibGfx/ImageFormats/WebPLoaderLossy.cpp b/Userland/Libraries/LibGfx/ImageFormats/WebPLoaderLossy.cpp
new file mode 100644
index 0000000000..928cddada0
--- /dev/null
+++ b/Userland/Libraries/LibGfx/ImageFormats/WebPLoaderLossy.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2023, Nico Weber <thakis@chromium.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <AK/Debug.h>
+#include <AK/Endian.h>
+#include <AK/Format.h>
+#include <AK/MemoryStream.h>
+#include <AK/Vector.h>
+#include <LibGfx/ImageFormats/WebPLoaderLossy.h>
+
+// Lossy format: https://datatracker.ietf.org/doc/html/rfc6386
+
+namespace Gfx {
+
+// 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"
+ErrorOr<VP8Header> decode_webp_chunk_VP8_header(ReadonlyBytes vp8_data)
+{
+ if (vp8_data.size() < 10)
+ return Error::from_string_literal("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_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 Error::from_string_literal("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 Error::from_string_literal("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 VP8Header { version, show_frame, size_of_first_partition, width, horizontal_scale, height, vertical_scale, vp8_data.slice(10) };
+}
+
+ErrorOr<NonnullRefPtr<Bitmap>> decode_webp_chunk_VP8_contents(VP8Header const& vp8_header, bool include_alpha_channel)
+{
+ auto bitmap_format = include_alpha_channel ? BitmapFormat::BGRA8888 : BitmapFormat::BGRx8888;
+
+ // Uncomment this to test ALPH decoding for WebP-lossy-with-alpha images while lossy decoding isn't implemented yet.
+#if 0
+ return Bitmap::create(bitmap_format, { vp8_header.width, vp8_header.height });
+#else
+ // FIXME: Implement webp lossy decoding.
+ (void)vp8_header;
+ (void)bitmap_format;
+ return Error::from_string_literal("WebPImageDecoderPlugin: decoding lossy webps not yet implemented");
+#endif
+}
+
+}
diff --git a/Userland/Libraries/LibGfx/ImageFormats/WebPLoaderLossy.h b/Userland/Libraries/LibGfx/ImageFormats/WebPLoaderLossy.h
new file mode 100644
index 0000000000..fdf19d61a4
--- /dev/null
+++ b/Userland/Libraries/LibGfx/ImageFormats/WebPLoaderLossy.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2023, Nico Weber <thakis@chromium.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/Span.h>
+#include <AK/Types.h>
+#include <LibGfx/Bitmap.h>
+
+namespace Gfx {
+
+struct VP8Header {
+ u8 version;
+ bool show_frame;
+ u32 size_of_first_partition;
+ u32 width;
+ u8 horizontal_scale;
+ u32 height;
+ u8 vertical_scale;
+ ReadonlyBytes lossy_data;
+};
+
+// Parses the header data in a VP8 chunk. Pass the payload of a `VP8 ` chunk, after the tag and after the tag's data size.
+ErrorOr<VP8Header> decode_webp_chunk_VP8_header(ReadonlyBytes vp8_data);
+
+ErrorOr<NonnullRefPtr<Bitmap>> decode_webp_chunk_VP8_contents(VP8Header const&, bool include_alpha_channel);
+
+}