LibGfx/WebPWriter: Remove a copy in the animated frame writing code path

This code path now also compresses to memory once, and then writes to
the output stream.

Since the animation writer has a SeekableStream, it could compress to
the stream directly and fix up offsets later. That's more complicated
though, and keeping the animated and non-animated code paths similar
seems nice. And the drawback is just temporary higher memory use, and
the used memory is smaller than the memory needed by the input bitmap.
This commit is contained in:
Nico Weber 2024-05-14 19:47:38 -04:00 committed by Andreas Kling
commit c0f67a0188
Notes: sideshowbarker 2024-07-16 22:11:09 +09:00

View file

@ -434,14 +434,11 @@ ErrorOr<void> WebPAnimationWriter::add_frame(Bitmap& bitmap, int duration_ms, In
if (at.x() < 0 || at.y() < 0 || at.x() + bitmap.width() > m_dimensions.width() || at.y() + bitmap.height() > m_dimensions.height())
return Error::from_string_literal("Frame does not fit in animation dimensions");
// FIXME: The whole writing-and-reading-into-buffer over-and-over is awkward and inefficient.
// Since we have a SeekableStream, we could write both the VP8L chunk header and the ANMF chunk header with a placeholder size,
// compress the frame data directly to the stream, and then go back and update the two sizes.
// That's pretty messy though, and the compressed image data is smaller than the uncompressed bitmap passed in. So we'll buffer it.
auto vp8l_data_bytes = TRY(compress_VP8L_image_data(bitmap));
AllocatingMemoryStream vp8l_chunk_stream;
TRY(write_VP8L_chunk(vp8l_chunk_stream, bitmap.width(), bitmap.height(), true, vp8l_data_bytes));
auto vp8l_chunk_bytes = TRY(vp8l_chunk_stream.read_until_eof());
ANMFChunkHeader chunk;
chunk.frame_x = static_cast<u32>(at.x());
chunk.frame_y = static_cast<u32>(at.y());
@ -451,10 +448,8 @@ ErrorOr<void> WebPAnimationWriter::add_frame(Bitmap& bitmap, int duration_ms, In
chunk.blending_method = ANMFChunkHeader::BlendingMethod::DoNotBlend;
chunk.disposal_method = ANMFChunkHeader::DisposalMethod::DoNotDispose;
TRY(write_ANMF_chunk_header(m_stream, chunk, vp8l_chunk_bytes.size()));
TRY(m_stream.write_until_depleted(vp8l_chunk_bytes));
VERIFY(vp8l_chunk_bytes.size() % 2 == 0);
TRY(write_ANMF_chunk_header(m_stream, chunk, compute_VP8L_chunk_size(vp8l_data_bytes)));
TRY(write_VP8L_chunk(m_stream, bitmap.width(), bitmap.height(), true, vp8l_data_bytes));
TRY(update_size_in_header());