mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-22 17:31:58 -05:00
LibGfx/PNGWriter: Add support for inter-frame compression of apngs
Brings wow.apng from 1.2M to 606K, while reducing encoding time from 233 ms to 167 ms. (For comparison, writing wow.webp currently takes 88ms and produces a 255K file. The input wow.gif is 184K.)
This commit is contained in:
parent
314d7d12ca
commit
0a4f8736e3
2 changed files with 38 additions and 1 deletions
|
@ -227,6 +227,40 @@ TEST_CASE(test_png_animation)
|
|||
expect_bitmaps_equal(*frame1.image, *rgba_bitmap);
|
||||
}
|
||||
|
||||
TEST_CASE(test_png_incremental_animation)
|
||||
{
|
||||
auto rgb_bitmap_1 = TRY_OR_FAIL(create_test_rgb_bitmap());
|
||||
|
||||
auto rgb_bitmap_2 = TRY_OR_FAIL(create_test_rgb_bitmap());
|
||||
|
||||
rgb_bitmap_2->scanline(3)[3] = Gfx::Color(Color::Red).value();
|
||||
|
||||
// 20 kiB is enough for two 47x33 frames.
|
||||
auto stream_buffer = TRY_OR_FAIL(ByteBuffer::create_uninitialized(20 * 1024));
|
||||
FixedMemoryStream stream { Bytes { stream_buffer } };
|
||||
|
||||
auto animation_writer = TRY_OR_FAIL(Gfx::PNGWriter::start_encoding_animation(stream, rgb_bitmap_1->size()));
|
||||
|
||||
TRY_OR_FAIL(animation_writer->add_frame(*rgb_bitmap_1, 100));
|
||||
TRY_OR_FAIL(animation_writer->add_frame_relative_to_last_frame(*rgb_bitmap_2, 200, *rgb_bitmap_1));
|
||||
|
||||
auto encoded_animation = ReadonlyBytes { stream_buffer.data(), stream.offset() };
|
||||
|
||||
auto decoded_animation_plugin = TRY_OR_FAIL(Gfx::PNGImageDecoderPlugin::create(encoded_animation));
|
||||
EXPECT(decoded_animation_plugin->is_animated());
|
||||
EXPECT_EQ(decoded_animation_plugin->frame_count(), 2u);
|
||||
EXPECT_EQ(decoded_animation_plugin->loop_count(), 0u);
|
||||
EXPECT_EQ(decoded_animation_plugin->size(), rgb_bitmap_1->size());
|
||||
|
||||
auto frame0 = TRY_OR_FAIL(decoded_animation_plugin->frame(0));
|
||||
EXPECT_EQ(frame0.duration, 100);
|
||||
expect_bitmaps_equal(*frame0.image, *rgb_bitmap_1);
|
||||
|
||||
auto frame1 = TRY_OR_FAIL(decoded_animation_plugin->frame(1));
|
||||
EXPECT_EQ(frame1.duration, 200);
|
||||
expect_bitmaps_equal(*frame1.image, *rgb_bitmap_2);
|
||||
}
|
||||
|
||||
TEST_CASE(test_qoi)
|
||||
{
|
||||
TRY_OR_FAIL((test_roundtrip<Gfx::QOIWriter, Gfx::QOIImageDecoderPlugin>(TRY_OR_FAIL(create_test_rgb_bitmap()))));
|
||||
|
|
|
@ -403,6 +403,7 @@ public:
|
|||
}
|
||||
|
||||
virtual ErrorOr<void> add_frame(Bitmap&, int, IntPoint, BlendMode) override;
|
||||
virtual bool can_blend_frames() const override { return true; }
|
||||
|
||||
private:
|
||||
PNGWriter m_writer;
|
||||
|
@ -419,7 +420,7 @@ private:
|
|||
PNGWriter::Options const m_options;
|
||||
};
|
||||
|
||||
ErrorOr<void> PNGAnimationWriter::add_frame(Bitmap& bitmap, int duration_ms, IntPoint at, BlendMode)
|
||||
ErrorOr<void> PNGAnimationWriter::add_frame(Bitmap& bitmap, int duration_ms, IntPoint at, BlendMode blend_mode)
|
||||
{
|
||||
++m_number_of_frames;
|
||||
bool const is_first_frame = m_number_of_frames == 1;
|
||||
|
@ -465,6 +466,8 @@ ErrorOr<void> PNGAnimationWriter::add_frame(Bitmap& bitmap, int duration_ms, Int
|
|||
fcTL_data.delay_denominator = 1000;
|
||||
fcTL_data.x_offset = at.x();
|
||||
fcTL_data.y_offset = at.y();
|
||||
if (blend_mode == BlendMode::Blend)
|
||||
fcTL_data.blend_operation = 1;
|
||||
TRY(m_writer.add_fcTL_chunk(fcTL_data));
|
||||
m_sequence_number++;
|
||||
|
||||
|
|
Loading…
Reference in a new issue