Skip to content

Commit ae124c1

Browse files
LucasCholletawesomekling
authored andcommitted
LibGfx: Don't assume that a scan include all components for the image
A scan can contain fewer components that the full image. However, if there is multiple components, they have to follow the ordering of the frame header. It means that we can loop over components of the image and skip those that doesn't correspond.
1 parent 947698f commit ae124c1

File tree

1 file changed

+18
-9
lines changed

1 file changed

+18
-9
lines changed

Userland/Libraries/LibGfx/JPEGLoader.cpp

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ struct Component {
135135
u8 vsample_factor { 1 }; // Vi, Vertical sampling factor
136136
u8 qtable_id { 0 }; // Tqi, Quantization table destination selector
137137

138-
// The JPEG specification does not specify which component correspond to
138+
// The JPEG specification does not specify which component corresponds to
139139
// Y, Cb or Cr. This field (actually the index in the parent Vector) will
140140
// act as an authority to determine the *real* component.
141141
// Please note that this is implementation specific.
@@ -547,30 +547,39 @@ static inline ErrorOr<Marker> read_marker_at_cursor(Stream& stream)
547547

548548
static ErrorOr<void> read_start_of_scan(AK::SeekableStream& stream, JPEGLoadingContext& context)
549549
{
550+
// B.2.3 - Scan header syntax
551+
550552
if (context.state < JPEGLoadingContext::State::FrameDecoded) {
551553
dbgln_if(JPEG_DEBUG, "{}: SOS found before reading a SOF!", TRY(stream.tell()));
552554
return Error::from_string_literal("SOS found before reading a SOF");
553555
}
554556

555557
u16 bytes_to_read = TRY(stream.read_value<BigEndian<u16>>()) - 2;
556558
TRY(ensure_bounds_okay(TRY(stream.tell()), bytes_to_read, context.data_size));
557-
[[maybe_unused]] u8 const component_count = TRY(stream.read_value<u8>());
559+
u8 const component_count = TRY(stream.read_value<u8>());
558560

559561
Scan current_scan;
560562

563+
Optional<u8> last_read;
564+
u8 component_read = 0;
561565
for (auto& component : context.components) {
562-
u8 component_id = TRY(stream.read_value<u8>());
566+
// See the Csj paragraph:
567+
// [...] the ordering in the scan header shall follow the ordering in the frame header.
568+
if (component_read == component_count)
569+
break;
563570

564-
if (component.id != component_id) {
565-
dbgln("JPEG decode failed (component.id != component_id)");
566-
return Error::from_string_literal("JPEG decode failed (component.id != component_id)");
567-
}
571+
if (!last_read.has_value())
572+
last_read = TRY(stream.read_value<u8>());
573+
574+
if (component.id != *last_read)
575+
continue;
568576

569577
u8 table_ids = TRY(stream.read_value<u8>());
570578

571-
ScanComponent scan_component { component, static_cast<u8>(table_ids >> 4), static_cast<u8>(table_ids & 0x0F) };
579+
current_scan.components.empend(component, static_cast<u8>(table_ids >> 4), static_cast<u8>(table_ids & 0x0F));
572580

573-
current_scan.components.append(scan_component);
581+
component_read++;
582+
last_read.clear();
574583
}
575584

576585
current_scan.spectral_selection_start = TRY(stream.read_value<u8>());

0 commit comments

Comments
 (0)