diff --git a/Tests/LibGfx/TestImageDecoder.cpp b/Tests/LibGfx/TestImageDecoder.cpp index eb2c5e4ffa..b449d4ea2f 100644 --- a/Tests/LibGfx/TestImageDecoder.cpp +++ b/Tests/LibGfx/TestImageDecoder.cpp @@ -489,6 +489,18 @@ TEST_CASE(test_tiff_rgb_alpha) EXPECT_EQ(frame.image->get_pixel(60, 75), Gfx::Color::NamedColor::Red); } +TEST_CASE(test_tiff_palette_alpha) +{ + auto file = MUST(Core::MappedFile::map(TEST_INPUT("tiff/rgb_palette_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/rgb_palette_alpha.tiff b/Tests/LibGfx/test-inputs/tiff/rgb_palette_alpha.tiff new file mode 100644 index 0000000000..bbd37e86c0 Binary files /dev/null and b/Tests/LibGfx/test-inputs/tiff/rgb_palette_alpha.tiff differ diff --git a/Userland/Libraries/LibGfx/ImageFormats/TIFFLoader.cpp b/Userland/Libraries/LibGfx/ImageFormats/TIFFLoader.cpp index a39f0e61cf..78f87d3b0c 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/TIFFLoader.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/TIFFLoader.cpp @@ -92,6 +92,7 @@ private: switch (*m_metadata.photometric_interpretation()) { case PhotometricInterpretation::WhiteIsZero: case PhotometricInterpretation::BlackIsZero: + case PhotometricInterpretation::RGBPalette: return 1; case PhotometricInterpretation::RGB: return 3; @@ -147,6 +148,29 @@ private: return Color(first_component, second_component, third_component, alpha); } + if (m_metadata.photometric_interpretation() == PhotometricInterpretation::RGBPalette) { + auto const index = TRY(stream.read_bits(bits_per_sample[0])); + auto const alpha = TRY(manage_extra_channels()); + + // SamplesPerPixel == 1 is a requirement for RGBPalette + // From description of PhotometricInterpretation in Section 8: Baseline Field Reference Guide + // "In a TIFF ColorMap, all the Red values come first, followed by the Green values, + // then the Blue values." + auto const size = 1 << (*m_metadata.bits_per_sample())[0]; + auto const red_offset = 0 * size; + auto const green_offset = 1 * size; + auto const blue_offset = 2 * size; + + auto const color_map = *m_metadata.color_map(); + + // FIXME: ColorMap's values are always 16-bits, stop truncating them when we support 16 bits bitmaps + return Color( + color_map[red_offset + index] >> 8, + color_map[green_offset + index] >> 8, + color_map[blue_offset + index] >> 8, + alpha); + } + if (*m_metadata.photometric_interpretation() == PhotometricInterpretation::WhiteIsZero || *m_metadata.photometric_interpretation() == PhotometricInterpretation::BlackIsZero) { auto luminosity = TRY(read_component(stream, bits_per_sample[0])); diff --git a/Userland/Libraries/LibGfx/TIFFGenerator.py b/Userland/Libraries/LibGfx/TIFFGenerator.py index 3470a6465d..c655dca594 100755 --- a/Userland/Libraries/LibGfx/TIFFGenerator.py +++ b/Userland/Libraries/LibGfx/TIFFGenerator.py @@ -123,6 +123,7 @@ known_tags: List[Tag] = [ Tag('296', [TIFFType.UnsignedShort], [], ResolutionUnit.Inch, "ResolutionUnit", ResolutionUnit), Tag('339', [TIFFType.UnsignedShort], [], SampleFormat.Unsigned, "SampleFormat", SampleFormat), Tag('317', [TIFFType.UnsignedShort], [1], Predictor.NoPrediction, "Predictor", Predictor), + Tag('320', [TIFFType.UnsignedShort], [], None, "ColorMap"), Tag('338', [TIFFType.UnsignedShort], [], None, "ExtraSamples", ExtraSample), Tag('34675', [TIFFType.Undefined], [], None, "ICCProfile"), ]