diff options
author | Lucas CHOLLET <lucas.chollet@free.fr> | 2023-05-07 14:33:04 -0400 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2023-05-09 07:00:15 +0200 |
commit | 9b5050a11cb594a020f5c5328709935bc74d1963 (patch) | |
tree | 60592c93eab60d6aa7142936051b7a2ddf3aad5b /Userland | |
parent | fb6b52b3fb88c8043904dc0e94705222b9aa0493 (diff) | |
download | serenity-9b5050a11cb594a020f5c5328709935bc74d1963.zip |
LibGfx/JPEG: Add support for `SOF1` images
More precisely, it allows the decoder to try `SOF1` images. There are
still some sub-kind of this kind of JPEG that we don't support. In a
nutshell `SOF1` images allow more Huffman and quantization tables, 12
bits precision and arithmetic encoding. This patch only brings support
for the "more tables" part.
Please note that `SOF2` images are also allowed to have more tables, so
we gave the decoder the ability to handle these in the same time.
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibGfx/ImageFormats/JPEGLoader.cpp | 34 |
1 files changed, 25 insertions, 9 deletions
diff --git a/Userland/Libraries/LibGfx/ImageFormats/JPEGLoader.cpp b/Userland/Libraries/LibGfx/ImageFormats/JPEGLoader.cpp index 5fac9f4777..ba8e64b5c4 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/JPEGLoader.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/JPEGLoader.cpp @@ -73,6 +73,7 @@ #define JPEG_EOI 0xFFD9 #define JPEG_DRI 0XFFDD #define JPEG_SOF0 0XFFC0 +#define JPEG_SOF1 0XFFC1 #define JPEG_SOF2 0xFFC2 #define JPEG_SOF15 0xFFCF #define JPEG_SOI 0XFFD8 @@ -783,6 +784,7 @@ static inline bool is_supported_marker(Marker const marker) case JPEG_DRI: case JPEG_EOI: case JPEG_SOF0: + case JPEG_SOF1: case JPEG_SOF2: case JPEG_SOI: case JPEG_SOS: @@ -906,18 +908,22 @@ static ErrorOr<void> read_restart_interval(Stream& stream, JPEGLoadingContext& c static ErrorOr<void> read_huffman_table(Stream& stream, JPEGLoadingContext& context) { + // B.2.4.2 - Huffman table-specification syntax + u16 bytes_to_read = TRY(read_effective_chunk_size(stream)); while (bytes_to_read > 0) { HuffmanTable table; - u8 table_info = TRY(stream.read_value<u8>()); - u8 table_type = table_info >> 4; - u8 table_destination_id = table_info & 0x0F; + u8 const table_info = TRY(stream.read_value<u8>()); + u8 const table_type = table_info >> 4; + u8 const table_destination_id = table_info & 0x0F; if (table_type > 1) { dbgln_if(JPEG_DEBUG, "Unrecognized huffman table: {}!", table_type); return Error::from_string_literal("Unrecognized huffman table"); } - if (table_destination_id > 1) { + + if ((context.frame.type == StartOfFrame::FrameType::Baseline_DCT && table_destination_id > 1) + || (context.frame.type != StartOfFrame::FrameType::Baseline_DCT && table_destination_id > 3)) { dbgln_if(JPEG_DEBUG, "Invalid huffman table destination id: {}!", table_destination_id); return Error::from_string_literal("Invalid huffman table destination id"); } @@ -948,7 +954,6 @@ static ErrorOr<void> read_huffman_table(Stream& stream, JPEGLoadingContext& cont auto& huffman_table = table.type == 0 ? context.dc_tables : context.ac_tables; huffman_table.set(table.destination_id, table); - VERIFY(huffman_table.size() <= 2); bytes_to_read -= 1 + 16 + total_codes; } @@ -1124,6 +1129,18 @@ static inline void set_macroblock_metadata(JPEGLoadingContext& context) context.mblock_meta.total = context.mblock_meta.hcount * context.mblock_meta.vcount; } +static ErrorOr<void> ensure_standard_precision(StartOfFrame const& frame) +{ + // B.2.2 - Frame header syntax + // Table B.2 - Frame header parameter sizes and values + + if (frame.precision == 8) + return {}; + + dbgln_if(JPEG_DEBUG, "Unsupported precision: {}, for SOF type: {}!", frame.precision, static_cast<int>(frame.type)); + return Error::from_string_literal("Unsupported SOF precision."); +} + static ErrorOr<void> read_start_of_frame(Stream& stream, JPEGLoadingContext& context) { if (context.state == JPEGLoadingContext::FrameDecoded) { @@ -1134,10 +1151,8 @@ static ErrorOr<void> read_start_of_frame(Stream& stream, JPEGLoadingContext& con [[maybe_unused]] u16 const bytes_to_read = TRY(read_effective_chunk_size(stream)); context.frame.precision = TRY(stream.read_value<u8>()); - if (context.frame.precision != 8) { - dbgln_if(JPEG_DEBUG, "SOF precision != 8!"); - return Error::from_string_literal("SOF precision != 8"); - } + + TRY(ensure_standard_precision(context.frame)); context.frame.height = TRY(stream.read_value<BigEndian<u16>>()); context.frame.width = TRY(stream.read_value<BigEndian<u16>>()); @@ -1741,6 +1756,7 @@ static ErrorOr<void> parse_header(Stream& stream, JPEGLoadingContext& context) dbgln_if(JPEG_DEBUG, "Unexpected marker {:x}!", marker); return Error::from_string_literal("Unexpected marker"); case JPEG_SOF0: + case JPEG_SOF1: case JPEG_SOF2: TRY(read_start_of_frame(stream, context)); context.state = JPEGLoadingContext::FrameDecoded; |