1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 13:18:13 +00:00

LibGfx/WebP: Implement uncompressed ALPH chunk reading

ALPH chunks are only used to give lossy webp frames an alpha channel,
and lossy decompression isn't implemented yet. So this can currently
never be hit in practice -- but for debugging and testing, I put in
some code behind `#if 0` for now that fake-decompresses a lossy webp
frame by returning an empty bitmap.

But this also doesn't implement compressed ALPH chunks yet, and I
couldn't find any lossy-webp-with-alpha files that use uncompressed
alpha channels. So the code here isn't really tested.
This commit is contained in:
Nico Weber 2023-05-06 21:10:26 -04:00 committed by Andreas Kling
parent e9f5c9ab9d
commit fab6a3915e

View file

@ -303,8 +303,16 @@ static ErrorOr<NonnullRefPtr<Bitmap>> decode_webp_chunk_VP8(WebPLoadingContext&
{
VERIFY(vp8_chunk.type == FourCC("VP8 "));
// Uncomment this to test ALPH decoding for WebP-lossy-with-alpha images while lossy decoding isn't implemented yet.
#if 0
auto vp8_header = TRY(decode_webp_chunk_VP8_header(context, vp8_chunk));
// FIXME: probably want to pass in the bitmap format based on if there's an ALPH chunk.
return Bitmap::create(BitmapFormat::BGRA8888, { vp8_header.width, vp8_header.height });
#else
// FIXME: Implement webp lossy decoding.
return context.error("WebPImageDecoderPlugin: decoding lossy webps not yet implemented");
#endif
}
// https://developers.google.com/speed/webp/docs/riff_container#simple_file_format_lossless
@ -1300,6 +1308,41 @@ static ErrorOr<NonnullRefPtr<Bitmap>> decode_webp_chunk_VP8L(WebPLoadingContext&
return bitmap;
}
// https://developers.google.com/speed/webp/docs/riff_container#alpha
static ErrorOr<void> decode_webp_chunk_ALPH(WebPLoadingContext& context, Chunk const& alph_chunk, Bitmap& bitmap)
{
VERIFY(alph_chunk.type == FourCC("ALPH"));
if (alph_chunk.data.size() < 1)
return context.error("WebPImageDecoderPlugin: ALPH chunk too small");
u8 flags = alph_chunk.data.data()[0];
u8 preprocessing = (flags >> 4) & 3;
u8 filtering_method = (flags >> 2) & 3;
u8 compression_method = flags & 3;
dbgln_if(WEBP_DEBUG, "preprocessing {} filtering_method {} compression_method {}", preprocessing, filtering_method, compression_method);
ReadonlyBytes alpha_data = alph_chunk.data.slice(1);
if (compression_method == 0) {
// "Raw data: consists of a byte sequence of length width * height, containing all the 8-bit transparency values in scan order."
size_t pixel_count = bitmap.width() * bitmap.height();
if (alpha_data.size() < pixel_count)
return context.error("WebPImageDecoderPlugin: uncompressed ALPH data too small");
for (size_t i = 0; i < pixel_count; ++i)
bitmap.begin()[i] |= alpha_data[i] << 24;
return {};
}
// "Lossless format compression: the byte sequence is a compressed image-stream (as described in the WebP Lossless Bitstream Format)
// of implicit dimension width x height. That is, this image-stream does NOT contain any headers describing the image dimension.
// Once the image-stream is decoded into ARGB color values, following the process described in the lossless format specification,
// the transparency information must be extracted from the green channel of the ARGB quadruplet."
// FIXME
return context.error("WebPImageDecoderPlugin: compressed ALPH chunk processing not yet implemented");
}
static ErrorOr<VP8XHeader> decode_webp_chunk_VP8X(WebPLoadingContext& context, Chunk const& vp8x_chunk)
{
VERIFY(vp8x_chunk.type == FourCC("VP8X"));
@ -1594,9 +1637,8 @@ static ErrorOr<NonnullRefPtr<Bitmap>> decode_webp_image_data(WebPLoadingContext&
VERIFY(image_data.image_data_chunk->type == FourCC("VP8 "));
auto bitmap = TRY(decode_webp_chunk_VP8(context, image_data.image_data_chunk.value()));
if (image_data.alpha_chunk.has_value()) {
// FIXME: Decode alpha chunk and store decoded alpha in `bitmap`.
}
if (image_data.alpha_chunk.has_value())
TRY(decode_webp_chunk_ALPH(context, image_data.alpha_chunk.value(), *bitmap));
return bitmap;
}