From 2cfca633ca6b53e3996c16335fd7e0e7db916587 Mon Sep 17 00:00:00 2001 From: Lucas CHOLLET Date: Sat, 16 Dec 2023 23:05:41 -0500 Subject: [PATCH] LibGfx/TIFF: Add support for images with UnassociatedAlpha UnassociatedAlpha is the one used by GIMP when generating TIFF images with transparency. Support is added for Grayscale and RGB images as it's the two that we support right now but managing transparency should be really straightforward for other types as well. --- Tests/LibGfx/TestImageDecoder.cpp | 24 ++++++++++ .../test-inputs/tiff/grayscale_alpha.tiff | Bin 0 -> 240277 bytes Tests/LibGfx/test-inputs/tiff/rgb_alpha.tiff | Bin 0 -> 480891 bytes .../LibGfx/ImageFormats/TIFFLoader.cpp | 43 ++++++++++++++---- 4 files changed, 58 insertions(+), 9 deletions(-) create mode 100644 Tests/LibGfx/test-inputs/tiff/grayscale_alpha.tiff create mode 100644 Tests/LibGfx/test-inputs/tiff/rgb_alpha.tiff diff --git a/Tests/LibGfx/TestImageDecoder.cpp b/Tests/LibGfx/TestImageDecoder.cpp index e4823b61ad..eb2c5e4ffa 100644 --- a/Tests/LibGfx/TestImageDecoder.cpp +++ b/Tests/LibGfx/TestImageDecoder.cpp @@ -465,6 +465,30 @@ TEST_CASE(test_tiff_grayscale) EXPECT_EQ(frame.image->get_pixel(60, 75), Gfx::Color(130, 130, 130)); } +TEST_CASE(test_tiff_grayscale_alpha) +{ + auto file = MUST(Core::MappedFile::map(TEST_INPUT("tiff/grayscale_alpha.tiff"sv))); + EXPECT(Gfx::TIFFImageDecoderPlugin::sniff(file->bytes())); + auto plugin_decoder = TRY_OR_FAIL(Gfx::TIFFImageDecoderPlugin::create(file->bytes())); + + auto frame = TRY_OR_FAIL(expect_single_frame_of_size(*plugin_decoder, { 400, 300 })); + + EXPECT_EQ(frame.image->get_pixel(0, 0).alpha(), 0); + EXPECT_EQ(frame.image->get_pixel(60, 75), Gfx::Color(130, 130, 130)); +} + +TEST_CASE(test_tiff_rgb_alpha) +{ + auto file = MUST(Core::MappedFile::map(TEST_INPUT("tiff/rgb_alpha.tiff"sv))); + EXPECT(Gfx::TIFFImageDecoderPlugin::sniff(file->bytes())); + auto plugin_decoder = TRY_OR_FAIL(Gfx::TIFFImageDecoderPlugin::create(file->bytes())); + + auto frame = TRY_OR_FAIL(expect_single_frame_of_size(*plugin_decoder, { 400, 300 })); + + EXPECT_EQ(frame.image->get_pixel(0, 0).alpha(), 0); + EXPECT_EQ(frame.image->get_pixel(60, 75), Gfx::Color::NamedColor::Red); +} + TEST_CASE(test_tiff_16_bits) { auto file = MUST(Core::MappedFile::map(TEST_INPUT("tiff/16_bits.tiff"sv))); diff --git a/Tests/LibGfx/test-inputs/tiff/grayscale_alpha.tiff b/Tests/LibGfx/test-inputs/tiff/grayscale_alpha.tiff new file mode 100644 index 0000000000000000000000000000000000000000..8d779b8586c3f48cb95ce942d6fd169b6a927671 GIT binary patch literal 240277 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 AdH?_b literal 0 HcmV?d00001 diff --git a/Tests/LibGfx/test-inputs/tiff/rgb_alpha.tiff b/Tests/LibGfx/test-inputs/tiff/rgb_alpha.tiff new file mode 100644 index 0000000000000000000000000000000000000000..4338e82504578b2a2f3247538e69bf4e467c362d GIT binary patch literal 480891 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 literal 0 HcmV?d00001 diff --git a/Userland/Libraries/LibGfx/ImageFormats/TIFFLoader.cpp b/Userland/Libraries/LibGfx/ImageFormats/TIFFLoader.cpp index 493d2a9dc0..a39f0e61cf 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/TIFFLoader.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/TIFFLoader.cpp @@ -100,6 +100,18 @@ private: } } + Optional alpha_channel_index() const + { + if (m_metadata.extra_samples().has_value()) { + auto const extra_samples = m_metadata.extra_samples().value(); + for (u8 i = 0; i < extra_samples.size(); ++i) { + if (extra_samples[i] == ExtraSample::UnassociatedAlpha) + return i + samples_for_photometric_interpretation(); + } + } + return OptionalNone {}; + } + ErrorOr read_color(BigEndianInputBitStream& stream) { auto bits_per_sample = *m_metadata.bits_per_sample(); @@ -107,19 +119,32 @@ private: // 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 {}; + auto manage_extra_channels = [&]() -> ErrorOr { + // Both unknown and alpha channels are considered as extra channels, so let's iterate over + // them, conserve the alpha value (if any) and discard everything else. + + auto const number_base_channels = samples_for_photometric_interpretation(); + auto const alpha_index = alpha_channel_index(); + + Optional alpha {}; + + for (u8 i = number_base_channels; i < bits_per_sample.size(); ++i) { + if (alpha_index == i) + alpha = TRY(read_component(stream, bits_per_sample[i])); + else + TRY(read_component(stream, bits_per_sample[i])); + } + + return alpha.value_or(NumericLimits::max()); }; 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); + + auto const alpha = TRY(manage_extra_channels()); + return Color(first_component, second_component, third_component, alpha); } if (*m_metadata.photometric_interpretation() == PhotometricInterpretation::WhiteIsZero @@ -129,8 +154,8 @@ private: if (m_metadata.photometric_interpretation() == PhotometricInterpretation::WhiteIsZero) luminosity = ~luminosity; - TRY(discard_unknown_channels()); - return Color(luminosity, luminosity, luminosity); + auto const alpha = TRY(manage_extra_channels()); + return Color(luminosity, luminosity, luminosity, alpha); } return Error::from_string_literal("Unsupported value for PhotometricInterpretation");