diff --git a/Tests/LibGfx/TestImageDecoder.cpp b/Tests/LibGfx/TestImageDecoder.cpp index 50f723bf67..40479c0eb3 100644 --- a/Tests/LibGfx/TestImageDecoder.cpp +++ b/Tests/LibGfx/TestImageDecoder.cpp @@ -431,6 +431,18 @@ TEST_CASE(test_tiff_grayscale) EXPECT_EQ(frame.image->get_pixel(60, 75), Gfx::Color(130, 130, 130)); } +TEST_CASE(test_tiff_16_bits) +{ + auto file = MUST(Core::MappedFile::map(TEST_INPUT("tiff/16_bits.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), Gfx::Color::NamedColor::White); + EXPECT_EQ(frame.image->get_pixel(60, 75), Gfx::Color::NamedColor::Red); +} + 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/16_bits.tiff b/Tests/LibGfx/test-inputs/tiff/16_bits.tiff new file mode 100644 index 0000000000..73b1368703 Binary files /dev/null and b/Tests/LibGfx/test-inputs/tiff/16_bits.tiff differ diff --git a/Userland/Libraries/LibGfx/ImageFormats/TIFFLoader.cpp b/Userland/Libraries/LibGfx/ImageFormats/TIFFLoader.cpp index ec71de91e7..ec4ffd5cbc 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/TIFFLoader.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/TIFFLoader.cpp @@ -76,6 +76,34 @@ private: BigEndian, }; + static ErrorOr read_component(BigEndianInputBitStream& stream, u8 bits) + { + // FIXME: This function truncates everything to 8-bits + auto const value = TRY(stream.read_bits(bits)); + + if (bits > 8) + return value >> (bits - 8); + return value << (8 - bits); + } + + ErrorOr read_color(BigEndianInputBitStream& stream) + { + auto bits_per_sample = *m_metadata.bits_per_sample(); + if (m_metadata.samples_per_pixel().value_or(3) == 3) { + 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])); + return Color(first_component, second_component, third_component); + } + + if (*m_metadata.samples_per_pixel() == 1) { + auto const luminosity = TRY(read_component(stream, bits_per_sample[0])); + return Color(luminosity, luminosity, luminosity); + } + + return Error::from_string_literal("Unsupported number of sample per pixel"); + } + template, u32> StripDecoder> ErrorOr loop_over_pixels(StripDecoder&& strip_decoder) { @@ -87,6 +115,7 @@ private: auto const decoded_bytes = TRY(strip_decoder(strip_byte_counts[strip_index])); auto decoded_strip = make(decoded_bytes); + auto decoded_stream = make(move(decoded_strip)); for (u32 row = 0; row < *m_metadata.rows_per_strip(); row++) { auto const scanline = row + *m_metadata.rows_per_strip() * strip_index; @@ -96,16 +125,7 @@ private: Optional last_color {}; for (u32 column = 0; column < *m_metadata.image_width(); ++column) { - 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"); - } + auto color = TRY(read_color(*decoded_stream)); if (m_metadata.predictor() == Predictor::HorizontalDifferencing && last_color.has_value()) { color.set_red(last_color->red() + color.red()); @@ -116,6 +136,8 @@ private: last_color = color; m_bitmap->set_pixel(column, scanline, color); } + + decoded_stream->align_to_byte_boundary(); } }