diff --git a/Userland/Libraries/LibGfx/ImageFormats/GIFWriter.cpp b/Userland/Libraries/LibGfx/ImageFormats/GIFWriter.cpp index 12b6897f786..20cca6e49c5 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/GIFWriter.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/GIFWriter.cpp @@ -167,6 +167,36 @@ ErrorOr GIFAnimationWriter::add_frame(Bitmap& bitmap, int duration_ms, Int return {}; } +ErrorOr write_netscape_extension(BigEndianOutputBitStream& stream, u16 loop_count) +{ + // This is a vendor extension, its sole usage is to provide the loop count. + // I used this link as a source: https://web.archive.org/web/19990418091037/http://www6.uniovi.es/gifanim/gifabout.htm + + // Extension Introducer + TRY(stream.write_value(0x21)); + // Application Extension Label + TRY(stream.write_value(0xFF)); + + // Block Size + constexpr auto netscape_signature = "NETSCAPE2.0"sv; + TRY(stream.write_value(netscape_signature.length())); + TRY(stream.write_until_depleted(netscape_signature)); + + // Length of Data Sub-Block + TRY(stream.write_value(3)); + + // Undocumented + TRY(stream.write_value(1)); + + // Number of loops, 0 means infinite + TRY(stream.write_value(loop_count)); + + // Block Terminator + TRY(stream.write_value(0)); + + return {}; +} + } ErrorOr GIFWriter::encode(Stream& stream, Bitmap const& bitmap) @@ -187,12 +217,16 @@ ErrorOr GIFWriter::encode(Stream& stream, Bitmap const& bitmap) return {}; } -ErrorOr> GIFWriter::start_encoding_animation(SeekableStream& stream, IntSize dimensions) +ErrorOr> GIFWriter::start_encoding_animation(SeekableStream& stream, IntSize dimensions, u16 loop_count) { TRY(write_header(stream)); BigEndianOutputBitStream bit_stream { MaybeOwned { stream } }; TRY(write_logical_descriptor(bit_stream, dimensions)); + + // Vendor extension to support looping + TRY(write_netscape_extension(bit_stream, loop_count)); + return make(stream); } diff --git a/Userland/Libraries/LibGfx/ImageFormats/GIFWriter.h b/Userland/Libraries/LibGfx/ImageFormats/GIFWriter.h index e959616f4d8..0139c565b62 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/GIFWriter.h +++ b/Userland/Libraries/LibGfx/ImageFormats/GIFWriter.h @@ -17,7 +17,7 @@ namespace Gfx { class GIFWriter { public: static ErrorOr encode(Stream&, Bitmap const&); - static ErrorOr> start_encoding_animation(SeekableStream&, IntSize dimensions); + static ErrorOr> start_encoding_animation(SeekableStream&, IntSize dimensions, u16 loop_count); }; } diff --git a/Userland/Utilities/animation.cpp b/Userland/Utilities/animation.cpp index ae7ca04830e..e91ba372a9f 100644 --- a/Userland/Utilities/animation.cpp +++ b/Userland/Utilities/animation.cpp @@ -51,7 +51,7 @@ ErrorOr serenity_main(Main::Arguments arguments) if (options.out_path.ends_with(".webp"sv)) return Gfx::WebPWriter::start_encoding_animation(*output_stream, decoder->size(), decoder->loop_count()); if (options.out_path.ends_with(".gif"sv)) - return Gfx::GIFWriter::start_encoding_animation(*output_stream, decoder->size()); + return Gfx::GIFWriter::start_encoding_animation(*output_stream, decoder->size(), decoder->loop_count()); return Error::from_string_literal("Unable to find a encoder for the requested extension."); }());