Skip to content

Commit b022ad1

Browse files
committed
Progressive images now render incomplete coefficients
Progressive jpegs have multiple passes on their spectral coefficients. This library currently waits for all coefficients to have been read in by the various segments before it sends the coefficient data to the DCT engine. However, some images have (perhaps incorrectly) incomplete passes on the coefficient data, where eg. a component might only have spectral coefficients 0 through 5 sent due to perhaps an improperly written encoder. In these scenarios this library would yield the error, 'not all components have data' instead of a more forgiving approach. This change adds a final pass over the components when in a progressive frame. The pass checks all components to determine if any have missing coefficients (ie. haven't been processed yet), and if this is the case it will send the components to the DCT engine to be processed, and then collected. This way, the library is more forgiving to incomplete spectral information present in certain progressive files. Added new crashtest image: * missing-sos: Image with a SOF but no SOS marker. Expected behavior is to yield the 'not all components have data' error Added new reftest images: * progressive-incomplete: Progressive image with only the DC component. Expected behavior should now be to render a white square. * progressive-missing-dc: Progressive image with only the first AC component. Expected behavior should be render a horizontal gradient.
1 parent 9cb72e5 commit b022ad1

File tree

8 files changed

+44
-0
lines changed

8 files changed

+44
-0
lines changed

src/decoder.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,46 @@ impl<R: Read> Decoder<R> {
410410
}
411411

412412
let frame = self.frame.as_ref().unwrap();
413+
414+
// If we're decoding a progressive jpeg and a component is unfinished, render what we've got
415+
if frame.coding_process == CodingProcess::DctProgressive && self.coefficients.len() == frame.components.len() {
416+
for (i, component) in frame.components.iter().enumerate() {
417+
// Only dealing with unfinished components
418+
if self.coefficients_finished[i] == !0 {
419+
continue;
420+
}
421+
422+
let quantization_table = match self.quantization_tables[component.quantization_table_index].clone() {
423+
Some(quantization_table) => quantization_table,
424+
None => continue,
425+
};
426+
427+
// Get the worker prepared
428+
if worker.is_none() {
429+
worker = Some(PlatformWorker::new()?);
430+
}
431+
let worker = worker.as_mut().unwrap();
432+
let row_data = RowData {
433+
index: i,
434+
component: component.clone(),
435+
quantization_table,
436+
};
437+
worker.start(row_data)?;
438+
439+
// Send the rows over to the worker and collect the result
440+
let coefficients_per_mcu_row = usize::from(component.block_size.width) * usize::from(component.vertical_sampling_factor) * 64;
441+
for mcu_y in 0..frame.mcu_size.height {
442+
let row_coefficients = {
443+
let offset = usize::from(mcu_y) * coefficients_per_mcu_row;
444+
self.coefficients[i][offset .. offset + coefficients_per_mcu_row].to_vec()
445+
};
446+
447+
worker.append_row((i, row_coefficients))?;
448+
}
449+
planes[i] = worker.get_result(i)?;
450+
}
451+
}
452+
413453
compute_image(&frame.components, planes, frame.output_size, self.is_jfif, self.color_transform)
414454
}
415455

tests/crashtest/images/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ dc-predictor-overflow.jpg | Found by Wim Looman (@Nemo157) while fuzzing
66
derive-huffman-codes-overflow.jpg | Found by Pascal Hertleif (@killercup) while fuzzing
77
missing-sof.jpg | Found by Corey Farwell (@frewsxcv) when fuzz testing
88
extraneous-bytes-after-sos.jpg | Scan from brother DSmobile 920DW provided by Filip Lundborg (@filipl)
9+
missing-sos.jpg | Generated in GIMP and manually edited by John Reynolds (@quilan1)
104 Bytes
Loading

tests/reftest/images/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,6 @@ mjpeg.jpg | https://bugzilla.mozilla.org/show_bug.cgi?id=963907
1010
restarts.jpg | `mozilla/jpg-size-33x33.jpg` with added restart markers.
1111
rgb.jpg | Created from `ycck.jpg` using <code>convert ycck.jpg tga:- &#124; cjpeg -rgb -outfile rgb.jpg</code>
1212
ycck.jpg | https://en.wikipedia.org/wiki/File:Channel_digital_image_CMYK_color.jpg
13+
non-interleaved-mcu.jpg | Generated in GIMP by John Reynolds (@quilan1)
14+
progressive-missing-ac.jpg | Generated in GIMP and manually edited by John Reynolds (@quilan1)
15+
progressive-missing-dc.jpg | Generated in GIMP and manually edited by John Reynolds (@quilan1)
139 Bytes
Loading
113 Bytes
Loading
139 Bytes
Loading
4.82 KB
Loading

0 commit comments

Comments
 (0)