From c0f67a0188429bd231b8fca1d67f805a82fad1ab Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Tue, 14 May 2024 19:47:38 -0400 Subject: [PATCH] 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. --- .../Libraries/LibGfx/ImageFormats/WebPWriter.cpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/Userland/Libraries/LibGfx/ImageFormats/WebPWriter.cpp b/Userland/Libraries/LibGfx/ImageFormats/WebPWriter.cpp index 3281e696e89..431f3231b7f 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/WebPWriter.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/WebPWriter.cpp @@ -434,14 +434,11 @@ ErrorOr 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(at.x()); chunk.frame_y = static_cast(at.y()); @@ -451,10 +448,8 @@ ErrorOr 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());