diff --git a/Meta/gn/secondary/Userland/Libraries/LibGfx/BUILD.gn b/Meta/gn/secondary/Userland/Libraries/LibGfx/BUILD.gn index 8c271e6b0dc..4d376034dc3 100644 --- a/Meta/gn/secondary/Userland/Libraries/LibGfx/BUILD.gn +++ b/Meta/gn/secondary/Userland/Libraries/LibGfx/BUILD.gn @@ -97,6 +97,7 @@ shared_library("LibGfx") { "ImageFormats/WebPLoader.cpp", "ImageFormats/WebPLoaderLossless.cpp", "ImageFormats/WebPLoaderLossy.cpp", + "ImageFormats/WebPSharedLossless.cpp", "ImageFormats/WebPWriter.cpp", "ImageFormats/WebPWriterLossless.cpp", "ImmutableBitmap.cpp", diff --git a/Userland/Libraries/LibGfx/CMakeLists.txt b/Userland/Libraries/LibGfx/CMakeLists.txt index 3ae75f02423..740c9c41dd1 100644 --- a/Userland/Libraries/LibGfx/CMakeLists.txt +++ b/Userland/Libraries/LibGfx/CMakeLists.txt @@ -71,6 +71,7 @@ set(SOURCES ImageFormats/WebPLoader.cpp ImageFormats/WebPLoaderLossless.cpp ImageFormats/WebPLoaderLossy.cpp + ImageFormats/WebPSharedLossless.cpp ImageFormats/WebPWriter.cpp ImageFormats/WebPWriterLossless.cpp ImmutableBitmap.cpp diff --git a/Userland/Libraries/LibGfx/ImageFormats/WebPLoaderLossless.cpp b/Userland/Libraries/LibGfx/ImageFormats/WebPLoaderLossless.cpp index 89954d9171f..dbf27b676f7 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/WebPLoaderLossless.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/WebPLoaderLossless.cpp @@ -12,6 +12,7 @@ #include #include #include +#include // Lossless format: https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification @@ -49,77 +50,6 @@ ErrorOr decode_webp_chunk_VP8L_header(ReadonlyBytes vp8l_data) return VP8LHeader { width, height, is_alpha_used, vp8l_data.slice(5) }; } -namespace { - -// WebP-lossless's CanonicalCodes are almost identical to deflate's. -// One difference is that codes with a single element in webp-lossless consume 0 bits to produce that single element, -// while they consume 1 bit in Compress::CanonicalCode. This class wraps Compress::CanonicalCode to handle the case -// where the codes contain just a single element, and dispatches to Compress::CanonicalCode else. -class CanonicalCode { -public: - CanonicalCode() - : m_code(0) - { - } - - static ErrorOr from_bytes(ReadonlyBytes); - ErrorOr read_symbol(LittleEndianInputBitStream&) const; - -private: - explicit CanonicalCode(u32 single_symbol) - : m_code(single_symbol) - { - } - - explicit CanonicalCode(Compress::CanonicalCode code) - : m_code(move(code)) - { - } - - Variant m_code; -}; - -ErrorOr CanonicalCode::from_bytes(ReadonlyBytes bytes) -{ - auto non_zero_symbol_count = 0; - auto last_non_zero_symbol = -1; - for (size_t i = 0; i < bytes.size(); i++) { - if (bytes[i] != 0) { - non_zero_symbol_count++; - last_non_zero_symbol = i; - } - } - - if (non_zero_symbol_count == 1) - return CanonicalCode(last_non_zero_symbol); - - return CanonicalCode(TRY(Compress::CanonicalCode::from_bytes(bytes))); -} - -ErrorOr CanonicalCode::read_symbol(LittleEndianInputBitStream& bit_stream) const -{ - return TRY(m_code.visit( - [](u32 single_code) -> ErrorOr { return single_code; }, - [&bit_stream](Compress::CanonicalCode const& code) { return code.read_symbol(bit_stream); })); -} - -// https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification#61_overview -// "From here on, we refer to this set as a prefix code group." -class PrefixCodeGroup { -public: - PrefixCodeGroup() = default; - PrefixCodeGroup(PrefixCodeGroup&&) = default; - PrefixCodeGroup(PrefixCodeGroup const&) = delete; - - CanonicalCode& operator[](int i) { return m_codes[i]; } - CanonicalCode const& operator[](int i) const { return m_codes[i]; } - -private: - Array m_codes; -}; - -} - // https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification#621_decoding_and_building_the_prefix_codes static ErrorOr decode_webp_chunk_VP8L_prefix_code(LittleEndianInputBitStream& bit_stream, size_t alphabet_size) { diff --git a/Userland/Libraries/LibGfx/ImageFormats/WebPSharedLossless.cpp b/Userland/Libraries/LibGfx/ImageFormats/WebPSharedLossless.cpp new file mode 100644 index 00000000000..3b5b4928e0e --- /dev/null +++ b/Userland/Libraries/LibGfx/ImageFormats/WebPSharedLossless.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024, Nico Weber + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +namespace Gfx { + +ErrorOr CanonicalCode::from_bytes(ReadonlyBytes bytes) +{ + auto non_zero_symbol_count = 0; + auto last_non_zero_symbol = -1; + for (size_t i = 0; i < bytes.size(); i++) { + if (bytes[i] != 0) { + non_zero_symbol_count++; + last_non_zero_symbol = i; + } + } + + if (non_zero_symbol_count == 1) + return CanonicalCode(last_non_zero_symbol); + + return CanonicalCode(TRY(Compress::CanonicalCode::from_bytes(bytes))); +} + +ErrorOr CanonicalCode::read_symbol(LittleEndianInputBitStream& bit_stream) const +{ + return TRY(m_code.visit( + [](u32 single_code) -> ErrorOr { return single_code; }, + [&bit_stream](Compress::CanonicalCode const& code) { return code.read_symbol(bit_stream); })); +} + +} diff --git a/Userland/Libraries/LibGfx/ImageFormats/WebPSharedLossless.h b/Userland/Libraries/LibGfx/ImageFormats/WebPSharedLossless.h new file mode 100644 index 00000000000..a49b9f14050 --- /dev/null +++ b/Userland/Libraries/LibGfx/ImageFormats/WebPSharedLossless.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024, Nico Weber + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Gfx { + +// WebP-lossless's CanonicalCodes are almost identical to deflate's. +// One difference is that codes with a single element in webp-lossless consume 0 bits to produce that single element, +// while they consume 1 bit in Compress::CanonicalCode. This class wraps Compress::CanonicalCode to handle the case +// where the codes contain just a single element, and dispatches to Compress::CanonicalCode else. +class CanonicalCode { +public: + CanonicalCode() + : m_code(0) + { + } + + static ErrorOr from_bytes(ReadonlyBytes); + ErrorOr read_symbol(LittleEndianInputBitStream&) const; + +private: + explicit CanonicalCode(u32 single_symbol) + : m_code(single_symbol) + { + } + + explicit CanonicalCode(Compress::CanonicalCode code) + : m_code(move(code)) + { + } + + Variant m_code; +}; + +// https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification#61_overview +// "From here on, we refer to this set as a prefix code group." +class PrefixCodeGroup { +public: + PrefixCodeGroup() = default; + PrefixCodeGroup(PrefixCodeGroup&&) = default; + PrefixCodeGroup(PrefixCodeGroup const&) = delete; + + CanonicalCode& operator[](int i) { return m_codes[i]; } + CanonicalCode const& operator[](int i) const { return m_codes[i]; } + +private: + Array m_codes; +}; + +}