LibGfx/TIFF: Add support for bit-depth up to 32 bits per sample

This makes us support every "minisblack" and "rgb-contig" images from
the depth folder of libtiff's test suite:
https://libtiff.gitlab.io/libtiff/images.html
This commit is contained in:
Lucas CHOLLET 2023-12-08 23:02:22 -05:00 committed by Andreas Kling
parent 25993cd93b
commit 234d084876
Notes: sideshowbarker 2024-07-17 17:49:11 +09:00
3 changed files with 44 additions and 10 deletions

View file

@ -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)));

Binary file not shown.

View file

@ -76,6 +76,34 @@ private:
BigEndian,
};
static ErrorOr<u8> read_component(BigEndianInputBitStream& stream, u8 bits)
{
// FIXME: This function truncates everything to 8-bits
auto const value = TRY(stream.read_bits<u32>(bits));
if (bits > 8)
return value >> (bits - 8);
return value << (8 - bits);
}
ErrorOr<Color> 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<CallableAs<ErrorOr<ReadonlyBytes>, u32> StripDecoder>
ErrorOr<void> 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<FixedMemoryStream>(decoded_bytes);
auto decoded_stream = make<BigEndianInputBitStream>(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<Color> 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<u8>()), TRY(decoded_strip->template read_value<u8>()), TRY(decoded_strip->template read_value<u8>()) };
} else if (*m_metadata.samples_per_pixel() == 1) {
auto luminosity = TRY(decoded_strip->template read_value<u8>());
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();
}
}