mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
LibGfx+animation: Support writing animated GIF files
This commit is contained in:
parent
6a5f8b5163
commit
777e84b09b
Notes:
sideshowbarker
2024-07-17 06:29:49 +09:00
Author: https://github.com/LucasChollet Commit: https://github.com/SerenityOS/serenity/commit/777e84b09b Pull-request: https://github.com/SerenityOS/serenity/pull/24380 Reviewed-by: https://github.com/nico ✅
3 changed files with 59 additions and 1 deletions
|
@ -127,6 +127,46 @@ ErrorOr<void> write_trailer(Stream& stream)
|
|||
return {};
|
||||
}
|
||||
|
||||
class GIFAnimationWriter : public AnimationWriter {
|
||||
public:
|
||||
GIFAnimationWriter(SeekableStream& stream)
|
||||
: m_stream(stream)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ErrorOr<void> add_frame(Bitmap&, int, IntPoint) override;
|
||||
|
||||
private:
|
||||
SeekableStream& m_stream;
|
||||
bool m_is_first_frame { true };
|
||||
};
|
||||
|
||||
ErrorOr<void> GIFAnimationWriter::add_frame(Bitmap& bitmap, int duration_ms, IntPoint at = {})
|
||||
{
|
||||
// FIXME: Consider frame's duration and position
|
||||
(void)duration_ms;
|
||||
(void)at;
|
||||
|
||||
// Let's get rid of the previously written trailer
|
||||
if (!m_is_first_frame)
|
||||
TRY(m_stream.seek(-1, SeekMode::FromEndPosition));
|
||||
|
||||
m_is_first_frame = false;
|
||||
|
||||
// Write a Table-Based Image
|
||||
BigEndianOutputBitStream bit_stream { MaybeOwned { m_stream } };
|
||||
TRY(write_image_descriptor(bit_stream, bitmap));
|
||||
|
||||
auto const palette = TRY(median_cut(bitmap, 256));
|
||||
TRY(write_color_table(m_stream, palette));
|
||||
TRY(write_image_data(m_stream, bitmap, palette));
|
||||
|
||||
// We always write a trailer to ensure that the file is valid.
|
||||
TRY(write_trailer(m_stream));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ErrorOr<void> GIFWriter::encode(Stream& stream, Bitmap const& bitmap)
|
||||
|
@ -147,4 +187,13 @@ ErrorOr<void> GIFWriter::encode(Stream& stream, Bitmap const& bitmap)
|
|||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<NonnullOwnPtr<AnimationWriter>> GIFWriter::start_encoding_animation(SeekableStream& stream, IntSize dimensions)
|
||||
{
|
||||
TRY(write_header(stream));
|
||||
|
||||
BigEndianOutputBitStream bit_stream { MaybeOwned<Stream> { stream } };
|
||||
TRY(write_logical_descriptor(bit_stream, dimensions));
|
||||
return make<GIFAnimationWriter>(stream);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <AK/Error.h>
|
||||
#include <LibGfx/Forward.h>
|
||||
#include <LibGfx/ImageFormats/AnimationWriter.h>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
|
@ -16,6 +17,7 @@ namespace Gfx {
|
|||
class GIFWriter {
|
||||
public:
|
||||
static ErrorOr<void> encode(Stream&, Bitmap const&);
|
||||
static ErrorOr<NonnullOwnPtr<AnimationWriter>> start_encoding_animation(SeekableStream&, IntSize dimensions);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <LibCore/File.h>
|
||||
#include <LibCore/MappedFile.h>
|
||||
#include <LibGfx/ImageFormats/AnimationWriter.h>
|
||||
#include <LibGfx/ImageFormats/GIFWriter.h>
|
||||
#include <LibGfx/ImageFormats/ImageDecoder.h>
|
||||
#include <LibGfx/ImageFormats/WebPWriter.h>
|
||||
|
||||
|
@ -46,7 +47,13 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
auto output_file = TRY(Core::File::open(options.out_path, Core::File::OpenMode::Write));
|
||||
auto output_stream = TRY(Core::OutputBufferedFile::create(move(output_file)));
|
||||
|
||||
auto animation_writer = TRY(Gfx::WebPWriter::start_encoding_animation(*output_stream, decoder->size(), decoder->loop_count()));
|
||||
auto animation_writer = TRY([&]() -> ErrorOr<NonnullOwnPtr<Gfx::AnimationWriter>> {
|
||||
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 Error::from_string_literal("Unable to find a encoder for the requested extension.");
|
||||
}());
|
||||
|
||||
RefPtr<Gfx::Bitmap> last_frame;
|
||||
for (size_t i = 0; i < decoder->frame_count(); ++i) {
|
||||
|
|
Loading…
Reference in a new issue