1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 00:47:45 +00:00

LibGfx: Implement WebPImageDecoderPlugin::loop_count()

Turns out extended-lossless-animated.webp did have a loop count of 0.
So I opened it in Hex Fiend and changed the byte at position 42
(which is the first byte of the little-endian u16 storing the loop
count) to 0x2A, so that the test can compare the loop count to something
not 0.
This commit is contained in:
Nico Weber 2023-02-26 09:13:27 -05:00 committed by Linus Groh
parent 3c5450b8be
commit fa34832297
3 changed files with 33 additions and 5 deletions

View file

@ -286,9 +286,7 @@ TEST_CASE(test_webp_extended_lossless_animated)
EXPECT_EQ(plugin_decoder->frame_count(), 8u); EXPECT_EQ(plugin_decoder->frame_count(), 8u);
EXPECT(plugin_decoder->is_animated()); EXPECT(plugin_decoder->is_animated());
EXPECT_EQ(plugin_decoder->loop_count(), 42u);
// FIXME: This is wrong.
EXPECT(!plugin_decoder->loop_count());
EXPECT_EQ(plugin_decoder->size(), Gfx::IntSize(990, 1050)); EXPECT_EQ(plugin_decoder->size(), Gfx::IntSize(990, 1050));
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Before After
Before After

View file

@ -79,6 +79,11 @@ struct VP8XHeader {
u32 height; u32 height;
}; };
struct ANIMChunk {
u32 background_color;
u16 loop_count;
};
} }
struct WebPLoadingContext { struct WebPLoadingContext {
@ -333,6 +338,20 @@ static ErrorOr<VP8XHeader> decode_webp_chunk_VP8X(WebPLoadingContext& context, C
return VP8XHeader { has_icc, has_alpha, has_exif, has_xmp, has_animation, width, height }; return VP8XHeader { has_icc, has_alpha, has_exif, has_xmp, has_animation, width, height };
} }
// https://developers.google.com/speed/webp/docs/riff_container#animation
static ErrorOr<ANIMChunk> decode_webp_chunk_ANIM(WebPLoadingContext& context, Chunk const& anim_chunk)
{
VERIFY(anim_chunk.type == FourCC("ANIM"));
if (anim_chunk.data.size() < 6)
return context.error("WebPImageDecoderPlugin: ANIM chunk too small");
u8 const* data = anim_chunk.data.data();
u32 background_color = (u32)data[0] | ((u32)data[1] << 8) | ((u32)data[2] << 16) | ((u32)data[3] << 24);
u16 loop_count = data[4] | (data[5] << 8);
return ANIMChunk { background_color, loop_count };
}
// https://developers.google.com/speed/webp/docs/riff_container#extended_file_format // https://developers.google.com/speed/webp/docs/riff_container#extended_file_format
static ErrorOr<void> decode_webp_extended(WebPLoadingContext& context, ReadonlyBytes chunks) static ErrorOr<void> decode_webp_extended(WebPLoadingContext& context, ReadonlyBytes chunks)
{ {
@ -532,8 +551,19 @@ bool WebPImageDecoderPlugin::is_animated()
size_t WebPImageDecoderPlugin::loop_count() size_t WebPImageDecoderPlugin::loop_count()
{ {
// FIXME if (!is_animated())
return 0; return 0;
if (m_context->state < WebPLoadingContext::State::ChunksDecoded) {
if (decode_webp_chunks(*m_context).is_error())
return 0;
}
auto anim_or_error = decode_webp_chunk_ANIM(*m_context, m_context->animation_header_chunk.value());
if (decode_webp_chunks(*m_context).is_error())
return 0;
return anim_or_error.value().loop_count;
} }
size_t WebPImageDecoderPlugin::frame_count() size_t WebPImageDecoderPlugin::frame_count()