mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 17:10:23 +00:00
LibGfx/TIFF: Add support for LZW compression
This commit is contained in:
parent
4f5a0227e2
commit
272be6b20a
Notes:
sideshowbarker
2024-07-17 04:01:41 +09:00
Author: https://github.com/LucasChollet Commit: https://github.com/SerenityOS/serenity/commit/272be6b20a Pull-request: https://github.com/SerenityOS/serenity/pull/21896
3 changed files with 56 additions and 1 deletions
|
@ -384,6 +384,18 @@ TEST_CASE(test_tiff_uncompressed)
|
|||
EXPECT_EQ(frame.image->get_pixel(60, 75), Gfx::Color::NamedColor::Red);
|
||||
}
|
||||
|
||||
TEST_CASE(test_tiff_lzw)
|
||||
{
|
||||
auto file = MUST(Core::MappedFile::map(TEST_INPUT("tiff/lzw.tiff"sv)));
|
||||
EXPECT(Gfx::TIFFImageDecoderPlugin::sniff(file->bytes()));
|
||||
auto plugin_decoder = MUST(Gfx::TIFFImageDecoderPlugin::create(file->bytes()));
|
||||
|
||||
auto frame = expect_single_frame_of_size(*plugin_decoder, { 400, 300 });
|
||||
|
||||
EXPECT_EQ(frame.image->get_pixel(0, 0), Gfx::Color::NamedColor::White);
|
||||
EXPECT_EQ(frame.image->get_pixel(60, 75), Gfx::Color::NamedColor::Red);
|
||||
}
|
||||
|
||||
TEST_CASE(test_tiff_packed_bits)
|
||||
{
|
||||
auto file = MUST(Core::MappedFile::map(TEST_INPUT("tiff/packed_bits.tiff"sv)));
|
||||
|
|
BIN
Tests/LibGfx/test-inputs/tiff/lzw.tiff
Normal file
BIN
Tests/LibGfx/test-inputs/tiff/lzw.tiff
Normal file
Binary file not shown.
|
@ -8,6 +8,7 @@
|
|||
#include <AK/Debug.h>
|
||||
#include <AK/Endian.h>
|
||||
#include <AK/String.h>
|
||||
#include <LibCompress/LZWDecoder.h>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
|
@ -108,10 +109,12 @@ private:
|
|||
};
|
||||
|
||||
template<typename ByteReader>
|
||||
ErrorOr<void> loop_over_pixels(ByteReader&& byte_reader)
|
||||
ErrorOr<void> loop_over_pixels(ByteReader&& byte_reader, Function<ErrorOr<void>(u32)> initializer = {})
|
||||
{
|
||||
for (u32 strip_index = 0; strip_index < m_strip_offsets.size(); ++strip_index) {
|
||||
TRY(m_stream->seek(m_strip_offsets[strip_index]));
|
||||
if (initializer)
|
||||
TRY(initializer(m_strip_bytes_count[strip_index]));
|
||||
for (u32 row = 0; row < m_rows_per_strip; row++) {
|
||||
auto const scanline = row + m_rows_per_strip * strip_index;
|
||||
if (scanline >= static_cast<u32>(m_size.height()))
|
||||
|
@ -145,6 +148,46 @@ private:
|
|||
case Compression::NoCompression:
|
||||
TRY(loop_over_pixels([this]() { return read_value<u8>(); }));
|
||||
break;
|
||||
case Compression::LZW: {
|
||||
Vector<u8> result_buffer {};
|
||||
Optional<Compress::LZWDecoder<BigEndianInputBitStream>> decoder {};
|
||||
|
||||
u16 clear_code {};
|
||||
u16 end_of_information_code {};
|
||||
|
||||
auto initializer = [&](u32 bytes) -> ErrorOr<void> {
|
||||
auto strip_stream = make<FixedMemoryStream>(TRY(m_stream->read_in_place<u8 const>(bytes)));
|
||||
auto lzw_stream = make<BigEndianInputBitStream>(MaybeOwned<Stream>(move(strip_stream)));
|
||||
decoder = Compress::LZWDecoder { MaybeOwned<BigEndianInputBitStream> { move(lzw_stream) }, 8, -1 };
|
||||
|
||||
clear_code = decoder->add_control_code();
|
||||
end_of_information_code = decoder->add_control_code();
|
||||
|
||||
return {};
|
||||
};
|
||||
|
||||
auto read_lzw_byte = [&]() -> ErrorOr<u8> {
|
||||
while (true) {
|
||||
if (!result_buffer.is_empty())
|
||||
return result_buffer.take_first();
|
||||
|
||||
auto const code = TRY(decoder->next_code());
|
||||
|
||||
if (code == clear_code) {
|
||||
decoder->reset();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (code == end_of_information_code)
|
||||
return Error::from_string_literal("TIFFImageDecoderPlugin: Reached end of LZW stream");
|
||||
|
||||
result_buffer = decoder->get_output();
|
||||
}
|
||||
};
|
||||
|
||||
TRY(loop_over_pixels([read_lzw_byte = move(read_lzw_byte)]() { return read_lzw_byte(); }, move(initializer)));
|
||||
break;
|
||||
}
|
||||
case Compression::PackBits: {
|
||||
// Section 9: PackBits Compression
|
||||
Optional<i8> n;
|
||||
|
|
Loading…
Reference in a new issue