From e6fc18d96aab3ac1efe9c2777e651318b8c8e9ec Mon Sep 17 00:00:00 2001 From: Lucas CHOLLET Date: Fri, 1 Dec 2023 20:37:59 -0500 Subject: [PATCH] LibGfx/TIFF: Support TIFF 5.0 LZW images This makes us decode `quad-lzw.tif` from libtiff's test suite: https://libtiff.gitlab.io/libtiff/images.html --- .../LibGfx/ImageFormats/TIFFLoader.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibGfx/ImageFormats/TIFFLoader.cpp b/Userland/Libraries/LibGfx/ImageFormats/TIFFLoader.cpp index 7984a8cd29..631e0e7327 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/TIFFLoader.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/TIFFLoader.cpp @@ -119,7 +119,23 @@ private: u32 read_head {}; auto initializer = [&](u32 bytes) -> ErrorOr { - decoded_bytes = TRY(Compress::LZWDecoder::decode_all(TRY(m_stream->read_in_place(bytes)), 8, -1)); + auto const encoded_bytes = TRY(m_stream->read_in_place(bytes)); + + if (encoded_bytes.is_empty()) + return Error::from_string_literal("TIFFImageDecoderPlugin: Unable to read from empty LZW strip"); + + // Note: AFAIK, there are two common ways to use LZW compression: + // - With a LittleEndian stream and no Early-Change, this is used in the GIF format + // - With a BigEndian stream and an EarlyChange of 1, this is used in the PDF format + // The fun begins when they decided to change from the former to the latter when moving + // from TIFF 5.0 to 6.0, and without including a way for files to be identified. + // Fortunately, as the first byte of a LZW stream is a constant we can guess the endianess + // and deduce the version from it. The first code is 0x100 (9-bits). + if (encoded_bytes[0] == 0x00) + decoded_bytes = TRY(Compress::LZWDecoder::decode_all(encoded_bytes, 8, 0)); + else + decoded_bytes = TRY(Compress::LZWDecoder::decode_all(encoded_bytes, 8, -1)); + read_head = 0; return {}; };