488 lines
14 KiB
Rust
488 lines
14 KiB
Rust
//! All IO functionality needed for TIFF decoding
|
|
|
|
use std::convert::TryFrom;
|
|
use std::io::{self, BufRead, BufReader, Read, Seek, SeekFrom, Take};
|
|
use std::sync::Arc;
|
|
|
|
/// Byte order of the TIFF file.
|
|
#[derive(Clone, Copy, Debug)]
|
|
pub enum ByteOrder {
|
|
/// little endian byte order
|
|
LittleEndian,
|
|
/// big endian byte order
|
|
BigEndian,
|
|
}
|
|
|
|
/// Reader that is aware of the byte order.
|
|
pub trait EndianReader: Read {
|
|
/// Byte order that should be adhered to
|
|
fn byte_order(&self) -> ByteOrder;
|
|
|
|
/// Reads an u16
|
|
#[inline(always)]
|
|
fn read_u16(&mut self) -> Result<u16, io::Error> {
|
|
let mut n = [0u8; 2];
|
|
self.read_exact(&mut n)?;
|
|
Ok(match self.byte_order() {
|
|
ByteOrder::LittleEndian => u16::from_le_bytes(n),
|
|
ByteOrder::BigEndian => u16::from_be_bytes(n),
|
|
})
|
|
}
|
|
|
|
/// Reads an i8
|
|
#[inline(always)]
|
|
fn read_i8(&mut self) -> Result<i8, io::Error> {
|
|
let mut n = [0u8; 1];
|
|
self.read_exact(&mut n)?;
|
|
Ok(match self.byte_order() {
|
|
ByteOrder::LittleEndian => i8::from_le_bytes(n),
|
|
ByteOrder::BigEndian => i8::from_be_bytes(n),
|
|
})
|
|
}
|
|
|
|
/// Reads an i16
|
|
#[inline(always)]
|
|
fn read_i16(&mut self) -> Result<i16, io::Error> {
|
|
let mut n = [0u8; 2];
|
|
self.read_exact(&mut n)?;
|
|
Ok(match self.byte_order() {
|
|
ByteOrder::LittleEndian => i16::from_le_bytes(n),
|
|
ByteOrder::BigEndian => i16::from_be_bytes(n),
|
|
})
|
|
}
|
|
|
|
/// Reads an u32
|
|
#[inline(always)]
|
|
fn read_u32(&mut self) -> Result<u32, io::Error> {
|
|
let mut n = [0u8; 4];
|
|
self.read_exact(&mut n)?;
|
|
Ok(match self.byte_order() {
|
|
ByteOrder::LittleEndian => u32::from_le_bytes(n),
|
|
ByteOrder::BigEndian => u32::from_be_bytes(n),
|
|
})
|
|
}
|
|
|
|
/// Reads an i32
|
|
#[inline(always)]
|
|
fn read_i32(&mut self) -> Result<i32, io::Error> {
|
|
let mut n = [0u8; 4];
|
|
self.read_exact(&mut n)?;
|
|
Ok(match self.byte_order() {
|
|
ByteOrder::LittleEndian => i32::from_le_bytes(n),
|
|
ByteOrder::BigEndian => i32::from_be_bytes(n),
|
|
})
|
|
}
|
|
|
|
/// Reads an u64
|
|
#[inline(always)]
|
|
fn read_u64(&mut self) -> Result<u64, io::Error> {
|
|
let mut n = [0u8; 8];
|
|
self.read_exact(&mut n)?;
|
|
Ok(match self.byte_order() {
|
|
ByteOrder::LittleEndian => u64::from_le_bytes(n),
|
|
ByteOrder::BigEndian => u64::from_be_bytes(n),
|
|
})
|
|
}
|
|
|
|
/// Reads an i64
|
|
#[inline(always)]
|
|
fn read_i64(&mut self) -> Result<i64, io::Error> {
|
|
let mut n = [0u8; 8];
|
|
self.read_exact(&mut n)?;
|
|
Ok(match self.byte_order() {
|
|
ByteOrder::LittleEndian => i64::from_le_bytes(n),
|
|
ByteOrder::BigEndian => i64::from_be_bytes(n),
|
|
})
|
|
}
|
|
|
|
/// Reads an f32
|
|
#[inline(always)]
|
|
fn read_f32(&mut self) -> Result<f32, io::Error> {
|
|
let mut n = [0u8; 4];
|
|
self.read_exact(&mut n)?;
|
|
Ok(f32::from_bits(match self.byte_order() {
|
|
ByteOrder::LittleEndian => u32::from_le_bytes(n),
|
|
ByteOrder::BigEndian => u32::from_be_bytes(n),
|
|
}))
|
|
}
|
|
|
|
/// Reads an f64
|
|
#[inline(always)]
|
|
fn read_f64(&mut self) -> Result<f64, io::Error> {
|
|
let mut n = [0u8; 8];
|
|
self.read_exact(&mut n)?;
|
|
Ok(f64::from_bits(match self.byte_order() {
|
|
ByteOrder::LittleEndian => u64::from_le_bytes(n),
|
|
ByteOrder::BigEndian => u64::from_be_bytes(n),
|
|
}))
|
|
}
|
|
}
|
|
|
|
///
|
|
/// # READERS
|
|
///
|
|
|
|
///
|
|
/// ## Deflate Reader
|
|
///
|
|
|
|
pub type DeflateReader<R> = flate2::read::ZlibDecoder<R>;
|
|
|
|
///
|
|
/// ## LZW Reader
|
|
///
|
|
|
|
/// Reader that decompresses LZW streams
|
|
pub struct LZWReader<R: Read> {
|
|
reader: BufReader<Take<R>>,
|
|
decoder: weezl::decode::Decoder,
|
|
}
|
|
|
|
impl<R: Read> LZWReader<R> {
|
|
/// Wraps a reader
|
|
pub fn new(reader: R, compressed_length: usize) -> LZWReader<R> {
|
|
Self {
|
|
reader: BufReader::with_capacity(
|
|
(32 * 1024).min(compressed_length),
|
|
reader.take(u64::try_from(compressed_length).unwrap()),
|
|
),
|
|
decoder: weezl::decode::Decoder::with_tiff_size_switch(weezl::BitOrder::Msb, 8),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<R: Read> Read for LZWReader<R> {
|
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
|
loop {
|
|
let result = self.decoder.decode_bytes(self.reader.fill_buf()?, buf);
|
|
self.reader.consume(result.consumed_in);
|
|
|
|
match result.status {
|
|
Ok(weezl::LzwStatus::Ok) => {
|
|
if result.consumed_out == 0 {
|
|
continue;
|
|
} else {
|
|
return Ok(result.consumed_out);
|
|
}
|
|
}
|
|
Ok(weezl::LzwStatus::NoProgress) => {
|
|
assert_eq!(result.consumed_in, 0);
|
|
assert_eq!(result.consumed_out, 0);
|
|
assert!(self.reader.buffer().is_empty());
|
|
return Err(io::Error::new(
|
|
io::ErrorKind::UnexpectedEof,
|
|
"no lzw end code found",
|
|
));
|
|
}
|
|
Ok(weezl::LzwStatus::Done) => {
|
|
return Ok(result.consumed_out);
|
|
}
|
|
Err(err) => return Err(io::Error::new(io::ErrorKind::InvalidData, err)),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
///
|
|
/// ## JPEG Reader (for "new-style" JPEG format (TIFF compression tag 7))
|
|
///
|
|
|
|
pub(crate) struct JpegReader {
|
|
jpeg_tables: Option<Arc<Vec<u8>>>,
|
|
|
|
buffer: io::Cursor<Vec<u8>>,
|
|
|
|
offset: usize,
|
|
}
|
|
|
|
impl JpegReader {
|
|
/// Constructs new JpegReader wrapping a SmartReader.
|
|
/// Because JPEG compression in TIFF allows to save quantization and/or huffman tables in one
|
|
/// central location, the constructor accepts this data as `jpeg_tables` here containing either
|
|
/// or both.
|
|
/// 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`).
|
|
pub fn new<R: Read>(
|
|
mut reader: R,
|
|
length: u64,
|
|
jpeg_tables: Option<Arc<Vec<u8>>>,
|
|
) -> io::Result<JpegReader> {
|
|
// Read jpeg image data
|
|
let mut segment = vec![0; length as usize];
|
|
|
|
reader.read_exact(&mut segment[..])?;
|
|
|
|
match jpeg_tables {
|
|
Some(jpeg_tables) => {
|
|
assert!(
|
|
jpeg_tables.len() >= 2,
|
|
"jpeg_tables, if given, must be at least 2 bytes long. Got {:?}",
|
|
jpeg_tables
|
|
);
|
|
|
|
assert!(
|
|
length >= 2,
|
|
"if jpeg_tables is given, length must be at least 2 bytes long, got {}",
|
|
length
|
|
);
|
|
|
|
let mut buffer = io::Cursor::new(segment);
|
|
// Skip the first two bytes (marker bytes)
|
|
buffer.seek(SeekFrom::Start(2))?;
|
|
|
|
Ok(JpegReader {
|
|
buffer,
|
|
jpeg_tables: Some(jpeg_tables),
|
|
offset: 0,
|
|
})
|
|
}
|
|
None => Ok(JpegReader {
|
|
buffer: io::Cursor::new(segment),
|
|
jpeg_tables: None,
|
|
offset: 0,
|
|
}),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[repr(u8)]
|
|
pub(crate) enum JpegTagApp14Transform {
|
|
// App14TransformYCCK = 2,
|
|
// App14TransformYCbCr = 1,
|
|
App14TransformUnknown = 0,
|
|
}
|
|
|
|
pub(crate) fn add_app14segment(jpeg_tables: &mut Vec<u8>, transform: JpegTagApp14Transform) {
|
|
// Add JPEG Tag APP14 Adobe segment to jpeg_tables.
|
|
// This segment stores image encoding information for DCT filters.
|
|
// When `transform` value is 0 which is defined as Unknown, jpeg-decoder interpret the
|
|
// color-space of image as RGB(3 channels) or CMYK(4).
|
|
let mut app14_offset = None;
|
|
let mut dht_offset = None;
|
|
for (offset, window) in jpeg_tables.windows(2).enumerate() {
|
|
if window == [0xff, 0xee] {
|
|
app14_offset = Some(offset);
|
|
break;
|
|
}
|
|
if window == [0xff, 0xc4] {
|
|
dht_offset = Some(offset);
|
|
}
|
|
}
|
|
match (app14_offset, dht_offset) {
|
|
(Some(i), _) => {
|
|
jpeg_tables[i + 16] = transform as u8;
|
|
}
|
|
(None, Some(sos_offset)) => {
|
|
let app14segment: [u8; 16] = [
|
|
0xff,
|
|
0xee,
|
|
0x00,
|
|
0x0e,
|
|
0x41,
|
|
0x64,
|
|
0x6f,
|
|
0x62,
|
|
0x65,
|
|
0x00,
|
|
0x64,
|
|
0x00,
|
|
0x00,
|
|
0x00,
|
|
0x00,
|
|
transform as u8,
|
|
];
|
|
jpeg_tables.splice(sos_offset..sos_offset, app14segment.iter().copied());
|
|
}
|
|
(None, None) => {}
|
|
}
|
|
}
|
|
|
|
impl Read for JpegReader {
|
|
// #[inline]
|
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
|
let mut start = 0;
|
|
|
|
if let Some(jpeg_tables) = &self.jpeg_tables {
|
|
if jpeg_tables.len() - 2 > self.offset {
|
|
// Read (rest of) jpeg_tables to buf (without the last two bytes)
|
|
let size_remaining = jpeg_tables.len() - self.offset - 2;
|
|
let to_copy = size_remaining.min(buf.len());
|
|
|
|
buf[start..start + to_copy]
|
|
.copy_from_slice(&jpeg_tables[self.offset..self.offset + to_copy]);
|
|
|
|
self.offset += to_copy;
|
|
|
|
if to_copy == buf.len() {
|
|
return Ok(to_copy);
|
|
}
|
|
|
|
start += to_copy;
|
|
}
|
|
}
|
|
|
|
let read = self.buffer.read(&mut buf[start..])?;
|
|
self.offset += read;
|
|
|
|
Ok(read + start)
|
|
}
|
|
}
|
|
|
|
///
|
|
/// ## PackBits Reader
|
|
///
|
|
|
|
enum PackBitsReaderState {
|
|
Header,
|
|
Literal,
|
|
Repeat { value: u8 },
|
|
}
|
|
|
|
/// Reader that unpacks Apple's `PackBits` format
|
|
pub struct PackBitsReader<R: Read> {
|
|
reader: Take<R>,
|
|
state: PackBitsReaderState,
|
|
count: usize,
|
|
}
|
|
|
|
impl<R: Read> PackBitsReader<R> {
|
|
/// Wraps a reader
|
|
pub fn new(reader: R, length: u64) -> Self {
|
|
Self {
|
|
reader: reader.take(length),
|
|
state: PackBitsReaderState::Header,
|
|
count: 0,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<R: Read> Read for PackBitsReader<R> {
|
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
|
while let PackBitsReaderState::Header = self.state {
|
|
if self.reader.limit() == 0 {
|
|
return Ok(0);
|
|
}
|
|
let mut header: [u8; 1] = [0];
|
|
self.reader.read_exact(&mut header)?;
|
|
let h = header[0] as i8;
|
|
if h >= -127 && h <= -1 {
|
|
let mut data: [u8; 1] = [0];
|
|
self.reader.read_exact(&mut data)?;
|
|
self.state = PackBitsReaderState::Repeat { value: data[0] };
|
|
self.count = (1 - h as isize) as usize;
|
|
} else if h >= 0 {
|
|
self.state = PackBitsReaderState::Literal;
|
|
self.count = h as usize + 1;
|
|
} else {
|
|
// h = -128 is a no-op.
|
|
}
|
|
}
|
|
|
|
let length = buf.len().min(self.count);
|
|
match self.state {
|
|
PackBitsReaderState::Literal => {
|
|
self.reader.read(&mut buf[..length])?;
|
|
}
|
|
PackBitsReaderState::Repeat { value } => {
|
|
for b in &mut buf[..length] {
|
|
*b = value;
|
|
}
|
|
}
|
|
PackBitsReaderState::Header => unreachable!(),
|
|
}
|
|
|
|
self.count -= length;
|
|
if self.count == 0 {
|
|
self.state = PackBitsReaderState::Header;
|
|
}
|
|
return Ok(length);
|
|
}
|
|
}
|
|
|
|
///
|
|
/// ## SmartReader Reader
|
|
///
|
|
|
|
/// Reader that is aware of the byte order.
|
|
#[derive(Debug)]
|
|
pub struct SmartReader<R>
|
|
where
|
|
R: Read,
|
|
{
|
|
reader: R,
|
|
pub byte_order: ByteOrder,
|
|
}
|
|
|
|
impl<R> SmartReader<R>
|
|
where
|
|
R: Read,
|
|
{
|
|
/// Wraps a reader
|
|
pub fn wrap(reader: R, byte_order: ByteOrder) -> SmartReader<R> {
|
|
SmartReader { reader, byte_order }
|
|
}
|
|
pub fn into_inner(self) -> R {
|
|
self.reader
|
|
}
|
|
}
|
|
impl<R: Read + Seek> SmartReader<R> {
|
|
pub fn goto_offset(&mut self, offset: u64) -> io::Result<()> {
|
|
self.seek(io::SeekFrom::Start(offset)).map(|_| ())
|
|
}
|
|
}
|
|
|
|
impl<R> EndianReader for SmartReader<R>
|
|
where
|
|
R: Read,
|
|
{
|
|
#[inline(always)]
|
|
fn byte_order(&self) -> ByteOrder {
|
|
self.byte_order
|
|
}
|
|
}
|
|
|
|
impl<R: Read> Read for SmartReader<R> {
|
|
#[inline]
|
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
|
self.reader.read(buf)
|
|
}
|
|
}
|
|
|
|
impl<R: Read + Seek> Seek for SmartReader<R> {
|
|
#[inline]
|
|
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
|
|
self.reader.seek(pos)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_packbits() {
|
|
let encoded = vec![
|
|
0xFE, 0xAA, 0x02, 0x80, 0x00, 0x2A, 0xFD, 0xAA, 0x03, 0x80, 0x00, 0x2A, 0x22, 0xF7,
|
|
0xAA,
|
|
];
|
|
let encoded_len = encoded.len();
|
|
|
|
let buff = io::Cursor::new(encoded);
|
|
let mut decoder = PackBitsReader::new(buff, encoded_len as u64);
|
|
|
|
let mut decoded = Vec::new();
|
|
decoder.read_to_end(&mut decoded).unwrap();
|
|
|
|
let expected = vec![
|
|
0xAA, 0xAA, 0xAA, 0x80, 0x00, 0x2A, 0xAA, 0xAA, 0xAA, 0xAA, 0x80, 0x00, 0x2A, 0x22,
|
|
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
|
];
|
|
assert_eq!(decoded, expected);
|
|
}
|
|
}
|