From caf9f004565cca8aafa67fecdf1f9cfb9ac511ff Mon Sep 17 00:00:00 2001 From: Lucas CHOLLET Date: Sat, 16 Dec 2023 20:25:49 -0500 Subject: [PATCH] LibGfx/TIFF: Skip channels that we are unable to interpret As per the specification, TIFF readers should gracefully skip samples that they are not able to interpret. This patch allow us to read `strike.tif` from the libtiff test suite as an RGB image. --- .../LibGfx/ImageFormats/TIFFLoader.cpp | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Userland/Libraries/LibGfx/ImageFormats/TIFFLoader.cpp b/Userland/Libraries/LibGfx/ImageFormats/TIFFLoader.cpp index fef21de45f..493d2a9dc0 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/TIFFLoader.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/TIFFLoader.cpp @@ -87,13 +87,38 @@ private: return NumericLimits::max() * value / ((1 << bits) - 1); } + u8 samples_for_photometric_interpretation() const + { + switch (*m_metadata.photometric_interpretation()) { + case PhotometricInterpretation::WhiteIsZero: + case PhotometricInterpretation::BlackIsZero: + return 1; + case PhotometricInterpretation::RGB: + return 3; + default: + TODO(); + } + } + ErrorOr read_color(BigEndianInputBitStream& stream) { auto bits_per_sample = *m_metadata.bits_per_sample(); + + // Section 7: Additional Baseline TIFF Requirements + // Some TIFF files may have more components per pixel than you think. A Baseline TIFF reader must skip over + // them gracefully, using the values of the SamplesPerPixel and BitsPerSample fields. + auto discard_unknown_channels = [&]() -> ErrorOr { + auto const unknown_channels = *m_metadata.samples_per_pixel() - samples_for_photometric_interpretation(); + for (u8 i = bits_per_sample.size() - unknown_channels; i < bits_per_sample.size(); ++i) + TRY(read_component(stream, bits_per_sample[i])); + return {}; + }; + if (m_metadata.photometric_interpretation() == PhotometricInterpretation::RGB) { auto const first_component = TRY(read_component(stream, bits_per_sample[0])); auto const second_component = TRY(read_component(stream, bits_per_sample[1])); auto const third_component = TRY(read_component(stream, bits_per_sample[2])); + TRY(discard_unknown_channels()); return Color(first_component, second_component, third_component); } @@ -104,6 +129,7 @@ private: if (m_metadata.photometric_interpretation() == PhotometricInterpretation::WhiteIsZero) luminosity = ~luminosity; + TRY(discard_unknown_channels()); return Color(luminosity, luminosity, luminosity); }