1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 02:17:34 +00:00

LibGfx/WebP: Extract an ImageData struct

We'll need the same struct for animation frames.
This commit is contained in:
Nico Weber 2023-05-05 20:17:11 -04:00 committed by Andreas Kling
parent 03b04ed66a
commit 1334bac548

View file

@ -109,6 +109,15 @@ struct ANMFChunk {
ReadonlyBytes frame_data; ReadonlyBytes frame_data;
}; };
// "For a still image, the image data consists of a single frame, which is made up of:
// An optional alpha subchunk.
// A bitstream subchunk."
struct ImageData {
// "This optional chunk contains encoded alpha data for this frame. A frame containing a 'VP8L' chunk SHOULD NOT contain this chunk."
Optional<Chunk> alpha_chunk; // 'ALPH'
Optional<Chunk> image_data_chunk; // Either 'VP8 ' or 'VP8L'. For 'VP8L', alpha_chunk will not have a value.
};
} }
struct WebPLoadingContext { struct WebPLoadingContext {
@ -139,13 +148,8 @@ struct WebPLoadingContext {
VP8XHeader vp8x_header; VP8XHeader vp8x_header;
}; };
// If first_chunk is not a VP8X chunk, then only image_data_chunk is set and all the other Chunks are not set. // If first_chunk is not a VP8X chunk, then only image_data.image_data_chunk is set and all the other Chunks are not set.
ImageData image_data;
// "For a still image, the image data consists of a single frame, which is made up of:
// An optional alpha subchunk.
// A bitstream subchunk."
Optional<Chunk> alpha_chunk; // 'ALPH'
Optional<Chunk> image_data_chunk; // Either 'VP8 ' or 'VP8L'.
Optional<Chunk> animation_header_chunk; // 'ANIM' Optional<Chunk> animation_header_chunk; // 'ANIM'
Vector<Chunk> animation_frame_chunks; // 'ANMF' Vector<Chunk> animation_frame_chunks; // 'ANMF'
@ -1414,7 +1418,7 @@ static ErrorOr<void> decode_webp_extended(WebPLoadingContext& context, ReadonlyB
if (chunk.type == FourCC("ICCP")) if (chunk.type == FourCC("ICCP"))
store(context.iccp_chunk, chunk); store(context.iccp_chunk, chunk);
else if (chunk.type == FourCC("ALPH")) else if (chunk.type == FourCC("ALPH"))
store(context.alpha_chunk, chunk); store(context.image_data.alpha_chunk, chunk);
else if (chunk.type == FourCC("ANIM")) else if (chunk.type == FourCC("ANIM"))
store(context.animation_header_chunk, chunk); store(context.animation_header_chunk, chunk);
else if (chunk.type == FourCC("ANMF")) else if (chunk.type == FourCC("ANMF"))
@ -1424,7 +1428,7 @@ static ErrorOr<void> decode_webp_extended(WebPLoadingContext& context, ReadonlyB
else if (chunk.type == FourCC("XMP ")) else if (chunk.type == FourCC("XMP "))
store(context.xmp_chunk, chunk); store(context.xmp_chunk, chunk);
else if (chunk.type == FourCC("VP8 ") || chunk.type == FourCC("VP8L")) else if (chunk.type == FourCC("VP8 ") || chunk.type == FourCC("VP8L"))
store(context.image_data_chunk, chunk); store(context.image_data.image_data_chunk, chunk);
} }
// Validate chunks. // Validate chunks.
@ -1447,16 +1451,16 @@ static ErrorOr<void> decode_webp_extended(WebPLoadingContext& context, ReadonlyB
// https://developers.google.com/speed/webp/docs/riff_container#alpha // https://developers.google.com/speed/webp/docs/riff_container#alpha
// "A frame containing a 'VP8L' chunk SHOULD NOT contain this chunk." // "A frame containing a 'VP8L' chunk SHOULD NOT contain this chunk."
// FIXME: Also check in ANMF chunks. // FIXME: Also check in ANMF chunks.
if (context.alpha_chunk.has_value() && context.image_data_chunk.has_value() && context.image_data_chunk->type == FourCC("VP8L")) { if (context.image_data.alpha_chunk.has_value() && context.image_data.image_data_chunk.has_value() && context.image_data.image_data_chunk->type == FourCC("VP8L")) {
dbgln_if(WEBP_DEBUG, "WebPImageDecoderPlugin: VP8L frames should not have ALPH chunks. Ignoring ALPH chunk."); dbgln_if(WEBP_DEBUG, "WebPImageDecoderPlugin: VP8L frames should not have ALPH chunks. Ignoring ALPH chunk.");
context.alpha_chunk.clear(); context.image_data.alpha_chunk.clear();
} }
// https://developers.google.com/speed/webp/docs/riff_container#color_profile // https://developers.google.com/speed/webp/docs/riff_container#color_profile
// "This chunk MUST appear before the image data." // "This chunk MUST appear before the image data."
if (context.iccp_chunk.has_value() if (context.iccp_chunk.has_value()
&& ((context.image_data_chunk.has_value() && context.iccp_chunk->data.data() > context.image_data_chunk->data.data()) && ((context.image_data.image_data_chunk.has_value() && context.iccp_chunk->data.data() > context.image_data.image_data_chunk->data.data())
|| (context.alpha_chunk.has_value() && context.iccp_chunk->data.data() > context.alpha_chunk->data.data()) || (context.image_data.alpha_chunk.has_value() && context.iccp_chunk->data.data() > context.image_data.alpha_chunk->data.data())
|| (!context.animation_frame_chunks.is_empty() && context.iccp_chunk->data.data() > context.animation_frame_chunks[0].data.data()))) { || (!context.animation_frame_chunks.is_empty() && context.iccp_chunk->data.data() > context.animation_frame_chunks[0].data.data()))) {
return context.error("WebPImageDecoderPlugin: ICCP chunk is after image data"); return context.error("WebPImageDecoderPlugin: ICCP chunk is after image data");
} }
@ -1483,7 +1487,7 @@ static ErrorOr<void> read_webp_first_chunk(WebPLoadingContext& context)
context.state = WebPLoadingContext::State::FirstChunkRead; context.state = WebPLoadingContext::State::FirstChunkRead;
if (first_chunk.type == FourCC("VP8 ") || first_chunk.type == FourCC("VP8L")) if (first_chunk.type == FourCC("VP8 ") || first_chunk.type == FourCC("VP8L"))
context.image_data_chunk = first_chunk; context.image_data.image_data_chunk = first_chunk;
return {}; return {};
} }
@ -1662,9 +1666,9 @@ ErrorOr<ImageFrameDescriptor> WebPImageDecoderPlugin::frame(size_t index)
return Error::from_string_literal("WebPImageDecoderPlugin: decoding of animated files not yet implemented"); return Error::from_string_literal("WebPImageDecoderPlugin: decoding of animated files not yet implemented");
} }
if (m_context->image_data_chunk.has_value() && m_context->image_data_chunk->type == FourCC("VP8L")) { if (m_context->image_data.image_data_chunk.has_value() && m_context->image_data.image_data_chunk->type == FourCC("VP8L")) {
if (m_context->state < WebPLoadingContext::State::BitmapDecoded) { if (m_context->state < WebPLoadingContext::State::BitmapDecoded) {
TRY(decode_webp_chunk_VP8L(*m_context, m_context->image_data_chunk.value())); TRY(decode_webp_chunk_VP8L(*m_context, m_context->image_data.image_data_chunk.value()));
m_context->state = WebPLoadingContext::State::BitmapDecoded; m_context->state = WebPLoadingContext::State::BitmapDecoded;
} }