Simplify and avoid allocation in jpeg decompression

This commit is contained in:
Jonathan Behrens committed 2023-06-11 12:54:30 -07:00
1 parent 289fab2fcd
commit 24d203c7c3
2 files changed
+27 -105

No files matched your search

+26 -5
View File
@@ -1,5 +1,5 @@
use super::ifd::{Directory, Value};
use super::stream::{ByteOrder, DeflateReader, JpegReader, LZWReader, PackBitsReader};
use super::stream::{ByteOrder, DeflateReader, LZWReader, PackBitsReader};
use super::tag_reader::TagReader;
use super::{fp_predict_f32, fp_predict_f64, DecodingBuffer, Limits};
use super::{stream::SmartReader, ChunkType};
@@ -326,7 +326,7 @@ impl Image {
photometric_interpretation: PhotometricInterpretation,
compression_method: CompressionMethod,
compressed_length: u64,
jpeg_tables: Option<Arc<Vec<u8>>>,
jpeg_tables: Option<&[u8]>,
) -> TiffResult<Box<dyn Read + 'r>> {
Ok(match compression_method {
CompressionMethod::None => Box::new(reader),
@@ -344,7 +344,29 @@ impl Image {
));
}
let jpeg_reader = JpegReader::new(reader, compressed_length, jpeg_tables)?;
// Construct new jpeg_reader wrapping a SmartReader.
//
// JPEG compression in TIFF allows saving quantization and/or huffman tables in one
// central location. These `jpeg_tables` are simply prepended to the remaining jpeg image data.
// Because these `jpeg_tables` start with a `SOI` (HEX: `0xFFD8`) or __start of image__ marker
// which is also at the beginning of the remaining JPEG image data and would
// confuse the JPEG renderer, one of these has to be taken off. In this case the first two
// bytes of the remaining JPEG data is removed because it follows `jpeg_tables`.
// Similary, `jpeg_tables` ends with a `EOI` (HEX: `0xFFD9`) or __end of image__ marker,
// this has to be removed as well (last two bytes of `jpeg_tables`).
let jpeg_reader = match jpeg_tables {
Some(jpeg_tables) => {
let mut reader = reader.take(compressed_length);
reader.read_exact(&mut [0; 2])?;
Box::new(
Cursor::new(&jpeg_tables[..jpeg_tables.len() - 2])
.chain(reader.take(compressed_length)),
) as Box<dyn Read>
}
None => Box::new(reader.take(compressed_length)),
};
let mut decoder = jpeg::Decoder::new(jpeg_reader);
match photometric_interpretation {
@@ -522,13 +544,12 @@ impl Image {
let padding_right = chunk_dims.0 - data_dims.0;
let jpeg_tables = self.jpeg_tables.clone();
let mut reader = Self::create_reader(
reader,
photometric_interpretation,
compression_method,
*compressed_bytes,
jpeg_tables,
self.jpeg_tables.as_deref().map(|a| &**a),
)?;
if output_width == data_dims.0 as usize && padding_right == 0 {