diff options
author | Nico Weber <thakis@chromium.org> | 2023-04-06 21:19:45 -0400 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2023-04-08 16:50:40 +0200 |
commit | a915d07293920c1ab9acc9e80556a89e94fbd19e (patch) | |
tree | e84d6f44650e296b58ad7f8d66a9dee61a17a281 | |
parent | 6f4fdd85b711832ba9913094401bc6e624ae1945 (diff) | |
download | serenity-a915d07293920c1ab9acc9e80556a89e94fbd19e.zip |
LibGfx: Implement most of COLOR_INDEXING_TRANSFORM for webp decoder
Doesn't yet implement pixel packing for when the palette has fewer
than 16 colors.
-rw-r--r-- | Userland/Libraries/LibGfx/ImageFormats/WebPLoader.cpp | 55 |
1 files changed, 54 insertions, 1 deletions
diff --git a/Userland/Libraries/LibGfx/ImageFormats/WebPLoader.cpp b/Userland/Libraries/LibGfx/ImageFormats/WebPLoader.cpp index 4a7ee549a9..997b2d4b88 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/WebPLoader.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/WebPLoader.cpp @@ -1062,6 +1062,58 @@ ErrorOr<void> SubtractGreenTransform::transform(Bitmap& bitmap) return {}; } +// https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification#44_color_indexing_transform +class ColorIndexingTransform : public Transform { +public: + static ErrorOr<NonnullOwnPtr<ColorIndexingTransform>> read(WebPLoadingContext&, LittleEndianInputBitStream&); + virtual ErrorOr<void> transform(Bitmap&) override; + +private: + explicit ColorIndexingTransform(NonnullRefPtr<Bitmap> palette_bitmap) + : m_palette_bitmap(palette_bitmap) + { + } + + NonnullRefPtr<Bitmap> m_palette_bitmap; +}; + +ErrorOr<NonnullOwnPtr<ColorIndexingTransform>> ColorIndexingTransform::read(WebPLoadingContext& context, LittleEndianInputBitStream& bit_stream) +{ + // color-indexing-image = 8BIT ; color count + // entropy-coded-image + int color_table_size = TRY(bit_stream.read_bits(8)) + 1; + IntSize palette_image_size { color_table_size, 1 }; + + // "When the color table is small (equal to or less than 16 colors), several pixels are bundled into a single pixel...." + // FIXME: Implement support for this pixel packing. + if (color_table_size <= 16) + return Error::from_string_literal("WebPImageDecoderPlugin: COLOR_INDEXING_TRANSFORM pixel packing not yet implemented"); + + auto palette_bitmap = TRY(decode_webp_chunk_VP8L_image(context, ImageKind::EntropyCoded, BitmapFormat::BGRA8888, palette_image_size, bit_stream)); + + // "The color table is always subtraction-coded to reduce image entropy. [...] In decoding, every final color in the color table + // can be obtained by adding the previous color component values by each ARGB component separately, + // and storing the least significant 8 bits of the result." + for (ARGB32* pixel = palette_bitmap->begin() + 1; pixel != palette_bitmap->end(); ++pixel) + *pixel = add_argb32(*pixel, pixel[-1]); + + return adopt_nonnull_own_or_enomem(new (nothrow) ColorIndexingTransform(move(palette_bitmap))); +} + +ErrorOr<void> ColorIndexingTransform::transform(Bitmap& bitmap) +{ + // FIXME: If this is the last transform, consider returning an Indexed8 bitmap here? + + for (ARGB32& pixel : bitmap) { + // "The inverse transform for the image is simply replacing the pixel values (which are indices to the color table) + // with the actual color table values. The indexing is done based on the green component of the ARGB color. [...] + // If the index is equal or larger than color_table_size, the argb color value should be set to 0x00000000 (transparent black)." + u8 index = Color::from_argb(pixel).green(); + pixel = index < m_palette_bitmap->width() ? m_palette_bitmap->scanline(0)[index] : 0; + } + return {}; +} + } // https://developers.google.com/speed/webp/docs/riff_container#simple_file_format_lossless @@ -1133,7 +1185,8 @@ static ErrorOr<void> decode_webp_chunk_VP8L(WebPLoadingContext& context, Chunk c TRY(transforms.try_append(TRY(try_make<SubtractGreenTransform>()))); break; case COLOR_INDEXING_TRANSFORM: - return context.error("WebPImageDecoderPlugin: VP8L COLOR_INDEXING_TRANSFORM handling not yet implemented"); + TRY(transforms.try_append(TRY(ColorIndexingTransform::read(context, bit_stream)))); + break; } } |