From da134f686755f8f30513d00bc66dcdcbccf1437b Mon Sep 17 00:00:00 2001 From: Lucas CHOLLET Date: Fri, 1 Dec 2023 19:28:06 -0500 Subject: [PATCH] LibGfx/TIFF: Add support for grayscale images Images with a single sample per pixel should be interpreted as grayscale. --- Tests/LibGfx/TestImageDecoder.cpp | 12 ++++++++++++ Tests/LibGfx/test-inputs/tiff/grayscale.tiff | Bin 0 -> 5801 bytes .../Libraries/LibGfx/ImageFormats/TIFFLoader.cpp | 11 ++++++++++- 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 Tests/LibGfx/test-inputs/tiff/grayscale.tiff diff --git a/Tests/LibGfx/TestImageDecoder.cpp b/Tests/LibGfx/TestImageDecoder.cpp index 725c6b06f5..fbec22eab9 100644 --- a/Tests/LibGfx/TestImageDecoder.cpp +++ b/Tests/LibGfx/TestImageDecoder.cpp @@ -408,6 +408,18 @@ TEST_CASE(test_tiff_packed_bits) EXPECT_EQ(frame.image->get_pixel(60, 75), Gfx::Color::NamedColor::Red); } +TEST_CASE(test_tiff_grayscale) +{ + auto file = MUST(Core::MappedFile::map(TEST_INPUT("tiff/grayscale.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(130, 130, 130)); +} + TEST_CASE(test_webp_simple_lossy) { auto file = MUST(Core::MappedFile::map(TEST_INPUT("webp/simple-vp8.webp"sv))); diff --git a/Tests/LibGfx/test-inputs/tiff/grayscale.tiff b/Tests/LibGfx/test-inputs/tiff/grayscale.tiff new file mode 100644 index 0000000000000000000000000000000000000000..2a025e3fac244a721b1dd9bef3d8ab27b76b88c7 GIT binary patch literal 5801 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 last_color {}; for (u32 column = 0; column < *m_metadata.image_width(); ++column) { - auto color = Color { TRY(decoded_strip->template read_value()), TRY(decoded_strip->template read_value()), TRY(decoded_strip->template read_value()) }; + Color color {}; + + if (m_metadata.samples_per_pixel().value_or(3) == 3) { + color = Color { TRY(decoded_strip->template read_value()), TRY(decoded_strip->template read_value()), TRY(decoded_strip->template read_value()) }; + } else if (*m_metadata.samples_per_pixel() == 1) { + auto luminosity = TRY(decoded_strip->template read_value()); + color = Color { luminosity, luminosity, luminosity }; + } else { + return Error::from_string_literal("Unsupported number of sample per pixel"); + } if (m_metadata.predictor() == Predictor::HorizontalDifferencing && last_color.has_value()) { color.set_red(last_color->red() + color.red());