mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-05-05 06:32:30 +02:00
LibGfx/JPEG2000: Add parsing loop for main header
We don't interpret any of the marker data yet.
This commit is contained in:
committed by
Andreas Kling
parent
6c9d3f8c46
commit
9eae6b3a90
Notes:
sideshowbarker
2024-07-17 00:23:42 +09:00
Author: https://github.com/nico Commit: https://github.com/SerenityOS/serenity/commit/9eae6b3a90 Pull-request: https://github.com/SerenityOS/serenity/pull/23888
@@ -66,6 +66,7 @@ struct JPEG2000LoadingContext {
|
||||
};
|
||||
State state { State::NotDecoded };
|
||||
ReadonlyBytes codestream_data;
|
||||
size_t codestream_cursor { 0 };
|
||||
Optional<ReadonlyBytes> icc_data;
|
||||
|
||||
IntSize size;
|
||||
@@ -73,6 +74,90 @@ struct JPEG2000LoadingContext {
|
||||
ISOBMFF::BoxList boxes;
|
||||
};
|
||||
|
||||
struct MarkerSegment {
|
||||
u16 marker;
|
||||
|
||||
// OptionalNone for markers that don't have data.
|
||||
// For markers that do have data, this does not include the marker length data. (`data.size() + 2` is the value of the marker length field.)
|
||||
Optional<ReadonlyBytes> data;
|
||||
};
|
||||
|
||||
static ErrorOr<u16> peek_marker(JPEG2000LoadingContext& context)
|
||||
{
|
||||
if (context.codestream_cursor + 2 > context.codestream_data.size())
|
||||
return Error::from_string_literal("JPEG2000ImageDecoderPlugin: Not enough data for marker");
|
||||
return *reinterpret_cast<AK::BigEndian<u16> const*>(context.codestream_data.data() + context.codestream_cursor);
|
||||
}
|
||||
|
||||
static ErrorOr<MarkerSegment> read_marker_at_cursor(JPEG2000LoadingContext& context)
|
||||
{
|
||||
u16 marker = TRY(peek_marker(context));
|
||||
// "All markers with the marker code between 0xFF30 and 0xFF3F have no marker segment parameters. They shall be skipped by the decoder."
|
||||
// "The SOC, SOD and EOC are delimiting markers not marker segments, and have no explicit length information or other parameters."
|
||||
bool is_marker_segment = !(marker >= 0xFF30 && marker <= 0xFF3F) && marker != J2K_SOC && marker != J2K_SOD && marker != J2K_EOC;
|
||||
|
||||
MarkerSegment marker_segment;
|
||||
marker_segment.marker = marker;
|
||||
|
||||
if (is_marker_segment) {
|
||||
if (context.codestream_cursor + 4 > context.codestream_data.size())
|
||||
return Error::from_string_literal("JPEG2000ImageDecoderPlugin: Not enough data for marker segment length");
|
||||
u16 marker_length = *reinterpret_cast<AK::BigEndian<u16> const*>(context.codestream_data.data() + context.codestream_cursor + 2);
|
||||
if (marker_length < 2)
|
||||
return Error::from_string_literal("JPEG2000ImageDecoderPlugin: Marker segment length too small");
|
||||
if (context.codestream_cursor + 2 + marker_length > context.codestream_data.size())
|
||||
return Error::from_string_literal("JPEG2000ImageDecoderPlugin: Not enough data for marker segment data");
|
||||
marker_segment.data = ReadonlyBytes { context.codestream_data.data() + context.codestream_cursor + 4, marker_length - 2u };
|
||||
}
|
||||
|
||||
context.codestream_cursor += 2;
|
||||
if (is_marker_segment)
|
||||
context.codestream_cursor += 2 + marker_segment.data->size();
|
||||
|
||||
return marker_segment;
|
||||
}
|
||||
|
||||
static ErrorOr<void> parse_codestream_main_header(JPEG2000LoadingContext& context)
|
||||
{
|
||||
// Figure A.3 – Construction of the main header
|
||||
// "Required as the first marker"
|
||||
auto marker = TRY(read_marker_at_cursor(context));
|
||||
if (marker.marker != J2K_SOC)
|
||||
return Error::from_string_literal("JPEG2000ImageDecoderPlugin: Expected SOC marker");
|
||||
|
||||
// "Required as the second marker segment"
|
||||
marker = TRY(read_marker_at_cursor(context));
|
||||
if (marker.marker != J2K_SIZ)
|
||||
return Error::from_string_literal("JPEG2000ImageDecoderPlugin: Expected SIZ marker");
|
||||
// FIXME: Parse SIZ marker.
|
||||
|
||||
while (true) {
|
||||
u16 marker = TRY(peek_marker(context));
|
||||
switch (marker) {
|
||||
case J2K_COD:
|
||||
case J2K_COC:
|
||||
case J2K_QCD:
|
||||
case J2K_QCC:
|
||||
case J2K_RGN:
|
||||
case J2K_POC:
|
||||
case J2K_PPM:
|
||||
case J2K_TLM:
|
||||
case J2K_PLM:
|
||||
case J2K_CRG:
|
||||
case J2K_COM: {
|
||||
// FIXME: These are valid main header markers. Parse contents.
|
||||
auto marker = TRY(read_marker_at_cursor(context));
|
||||
dbgln("JPEG2000ImageDecoderPlugin: marker {:#04x} not yet implemented", marker.marker);
|
||||
break;
|
||||
}
|
||||
case J2K_SOT:
|
||||
return {};
|
||||
default:
|
||||
return Error::from_string_literal("JPEG2000ImageDecoderPlugin: Unexpected marker in main header");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ErrorOr<void> decode_jpeg2000_header(JPEG2000LoadingContext& context, ReadonlyBytes data)
|
||||
{
|
||||
if (!JPEG2000ImageDecoderPlugin::sniff(data))
|
||||
@@ -163,6 +248,8 @@ static ErrorOr<void> decode_jpeg2000_header(JPEG2000LoadingContext& context, Rea
|
||||
if (color_header_box.method == 2 || color_header_box.method == 3)
|
||||
context.icc_data = color_header_box.icc_data.bytes();
|
||||
|
||||
TRY(parse_codestream_main_header(context));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user