diff --git a/Tests/LibGfx/TestImageWriter.cpp b/Tests/LibGfx/TestImageWriter.cpp index 60d811482d8..9272aaf26be 100644 --- a/Tests/LibGfx/TestImageWriter.cpp +++ b/Tests/LibGfx/TestImageWriter.cpp @@ -112,11 +112,8 @@ TEST_CASE(test_bmp) TEST_CASE(test_gif) { - auto bitmap = TRY_OR_FAIL(create_test_rgb_bitmap()); - - // We only support grayscale and non-animated images at the moment - convert bitmap to grayscale. - for (auto& argb : *bitmap) - argb = Color::from_argb(argb).to_grayscale().value(); + // Let's limit the size of the image so every color can fit in a color table of 256 elements. + auto bitmap = TRY_OR_FAIL(TRY_OR_FAIL(create_test_rgb_bitmap())->cropped({ 0, 0, 16, 16 })); auto encoded_bitmap = TRY_OR_FAIL((encode_bitmap(bitmap))); auto decoder = TRY_OR_FAIL(Gfx::GIFImageDecoderPlugin::create(encoded_bitmap)); diff --git a/Userland/Libraries/LibGfx/ImageFormats/GIFWriter.cpp b/Userland/Libraries/LibGfx/ImageFormats/GIFWriter.cpp index f3f43e5538a..1dc2fef4f9b 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/GIFWriter.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/GIFWriter.cpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace Gfx { @@ -49,29 +50,27 @@ ErrorOr write_logical_descriptor(BigEndianOutputBitStream& stream, Bitmap return {}; } -ErrorOr write_global_color_table(Stream& stream) +ErrorOr write_global_color_table(Stream& stream, ColorPalette const& palette) { // 19. Global Color Table - // FIXME: The color table should include color specific to the image for (u16 i = 0; i < 256; ++i) { - TRY(stream.write_value(i)); - TRY(stream.write_value(i)); - TRY(stream.write_value(i)); + auto const color = i < palette.palette().size() ? palette.palette()[i] : Color::NamedColor::White; + TRY(stream.write_value(color.red())); + TRY(stream.write_value(color.green())); + TRY(stream.write_value(color.blue())); } return {}; } -ErrorOr write_image_data(Stream& stream, Bitmap const& bitmap) +ErrorOr write_image_data(Stream& stream, Bitmap const& bitmap, ColorPalette const& palette) { // 22. Table Based Image Data auto const pixel_number = static_cast(bitmap.width() * bitmap.height()); auto indexes = TRY(ByteBuffer::create_uninitialized(pixel_number)); for (u32 i = 0; i < pixel_number; ++i) { auto const color = Color::from_argb(*(bitmap.begin() + i)); - if (color.red() != color.green() || color.green() != color.blue()) - return Error::from_string_literal("Non grayscale images are unsupported."); - indexes[i] = Color::from_argb(*(bitmap.begin() + i)).red(); // Any channel is correct + indexes[i] = palette.index_of_closest_color(color); } constexpr u8 lzw_minimum_code_size = 8; @@ -132,15 +131,16 @@ ErrorOr write_trailer(Stream& stream) ErrorOr GIFWriter::encode(Stream& stream, Bitmap const& bitmap) { + auto const palette = TRY(median_cut(bitmap, 256)); TRY(write_header(stream)); BigEndianOutputBitStream bit_stream { MaybeOwned { stream } }; TRY(write_logical_descriptor(bit_stream, bitmap)); - TRY(write_global_color_table(bit_stream)); + TRY(write_global_color_table(bit_stream, palette)); // Write a Table-Based Image TRY(write_image_descriptor(bit_stream, bitmap)); - TRY(write_image_data(stream, bitmap)); + TRY(write_image_data(stream, bitmap, palette)); TRY(write_trailer(bit_stream));