Add initial support for modern JPEG compression

Some things still need to be done:
- Check RGB images
- Check small images
- Check huffman-only jpeg tables
- Check empty jpeg tables
- Add tests
This commit is contained in:
ruffson committed 2020-09-25 19:42:29 +02:00
1 parent da9bdac8a2
commit 2cb57a4d04
5 files changed
+184 -1

No files matched your search

+86
View File
@@ -187,6 +187,14 @@ pub trait EndianReader: Read {
}
}
///
/// # READERS
///
///
/// ## Deflate Reader
///
/// Reader that decompresses DEFLATE streams
pub struct DeflateReader {
buffer: io::Cursor<Vec<u8>>,
@@ -233,6 +241,10 @@ impl EndianReader for DeflateReader {
}
}
///
/// ## LZW Reader
///
/// Reader that decompresses LZW streams
pub struct LZWReader {
buffer: io::Cursor<Vec<u8>>,
@@ -306,6 +318,76 @@ impl EndianReader for LZWReader {
}
}
///
/// ## JPEG Reader (for "new-style" JPEG format (TIFF compression tag 7))
///
pub struct JpegReader {
buffer: io::Cursor<Vec<u8>>,
byte_order: ByteOrder, // for jpeg image data always ...,
}
// Only tested with qtables in jpegtables, but it contain both qtables and huffman tables or either
impl JpegReader {
/// Constructs new JpegReader wrapping a SmartReader.
/// Because Jpeg compression in TIFF allows to save quantization and/or huffman tables in one
/// central loacation, the constructor accepts this data as `jpeg_tables` here containing either
/// both.
/// These `jpeg_tables` are simply prepended to the remaining jpeg image data.
/// Because these jpegtables 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 this 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`).
pub fn new<R>(
reader: &mut SmartReader<R>,
length: u32,
jpeg_tables: &Vec<u8>
) -> io::Result<JpegReader>
where
R: Read + Seek,
{
let order = reader.byte_order;
// Read jpeg image data
let mut segment = vec![0; length as usize];
reader.read_exact(&mut segment[..])?;
let mut jpeg_data = jpeg_tables.clone();
jpeg_data.truncate(jpeg_data.len() - 2);
jpeg_data.extend_from_slice(&mut segment[2..]);
Ok(
JpegReader {
buffer: io::Cursor::new(jpeg_data),
byte_order: order,
},
)
}
}
impl Read for JpegReader {
// #[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.buffer.read(buf)
}
}
impl EndianReader for JpegReader {
#[inline(always)]
fn byte_order(&self) -> ByteOrder {
self.byte_order
}
}
///
/// ## PackBits Reader
///
/// Reader that unpacks Apple's `PackBits` format
pub struct PackBitsReader {
buffer: io::Cursor<Vec<u8>>,
@@ -378,6 +460,10 @@ impl EndianReader for PackBitsReader {
}
}
///
/// ## SmartReader Reader
///
/// Reader that is aware of the byte order.
#[derive(Debug)]
pub struct SmartReader<R>