//! All IO functionality needed for TIFF decoding #[cfg(feature = "webp")] use std::io::Cursor; use std::io::{self, BufRead, BufReader, Read, Seek, Take}; pub use crate::tags::ByteOrder; /// Reader that is aware of the byte order. #[derive(Debug)] pub struct EndianReader { reader: R, pub(crate) byte_order: ByteOrder, } impl EndianReader { pub fn new(reader: R, byte_order: ByteOrder) -> Self { Self { reader, byte_order } } pub fn inner(&mut self) -> &mut R { &mut self.reader } pub fn goto_offset(&mut self, offset: u64) -> io::Result<()> where R: Seek, { self.reader.seek(io::SeekFrom::Start(offset))?; Ok(()) } /// Reads an u16 #[inline(always)] pub fn read_u16(&mut self) -> Result { let mut n = [0u8; 2]; self.reader.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 i16 #[inline(always)] pub fn read_i16(&mut self) -> Result { let mut n = [0u8; 2]; self.reader.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)] pub fn read_u32(&mut self) -> Result { let mut n = [0u8; 4]; self.reader.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)] pub fn read_i32(&mut self) -> Result { let mut n = [0u8; 4]; self.reader.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)] pub fn read_u64(&mut self) -> Result { let mut n = [0u8; 8]; self.reader.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)] pub fn read_i64(&mut self) -> Result { let mut n = [0u8; 8]; self.reader.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)] pub fn read_f32(&mut self) -> Result { let mut n = [0u8; 4]; self.reader.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)] pub fn read_f64(&mut self) -> Result { let mut n = [0u8; 8]; self.reader.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 // /// Type alias for the deflate Reader #[cfg(feature = "deflate")] pub type DeflateReader = flate2::read::ZlibDecoder; // // ## LZW Reader // /// Reader that decompresses LZW streams #[cfg(feature = "lzw")] pub struct LZWReader { reader: BufReader>, decoder: weezl::decode::Decoder, } #[cfg(feature = "lzw")] impl LZWReader { /// Wraps a reader pub fn new(reader: R, compressed_length: usize) -> LZWReader { let configuration = weezl::decode::Configuration::with_tiff_size_switch(weezl::BitOrder::Msb, 8) .with_yield_on_full_buffer(true); Self { reader: BufReader::with_capacity( (32 * 1024).min(compressed_length), reader.take(u64::try_from(compressed_length).unwrap()), ), decoder: configuration.build(), } } } #[cfg(feature = "lzw")] impl Read for LZWReader { fn read(&mut self, buf: &mut [u8]) -> io::Result { 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) => { 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)), } } } } // // ## PackBits Reader // /// Internal state machine for the PackBitsReader. enum PackBitsReaderState { Header, Literal, Repeat { value: u8 }, } /// Reader that unpacks Apple's `PackBits` format pub struct PackBitsReader { reader: Take, state: PackBitsReaderState, count: usize, } impl PackBitsReader { /// Wraps a reader pub fn new(reader: R, length: u64) -> Self { Self { reader: reader.take(length), state: PackBitsReaderState::Header, count: 0, } } } impl Read for PackBitsReader { fn read(&mut self, buf: &mut [u8]) -> io::Result { 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 (-127..=-1).contains(&h) { 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); let actual = match self.state { PackBitsReaderState::Literal => self.reader.read(&mut buf[..length])?, PackBitsReaderState::Repeat { value } => { for b in &mut buf[..length] { *b = value; } length } PackBitsReaderState::Header => unreachable!(), }; self.count -= actual; if self.count == 0 { self.state = PackBitsReaderState::Header; } Ok(actual) } } /// Iterator adapter that reverses bits in each byte for FillOrder=2 (LSB-to-MSB). #[cfg(feature = "fax")] type FaxBytes = core::iter::Map>>, fn(io::Result) -> io::Result>; #[cfg(feature = "fax")] fn fax_byte_iter(reader: R, len: u64, fill_order: u16) -> FaxBytes { let map_fn: fn(io::Result) -> io::Result = if fill_order == 2 { |r| r.map(u8::reverse_bits) } else { |r| r }; io::BufReader::new(reader.take(len)).bytes().map(map_fn) } #[cfg(feature = "fax")] pub struct Group4Reader { decoder: fax34::decoder::Group4Decoder>, line_buf: io::Cursor>, height: u32, width: u16, y: u32, } #[cfg(feature = "fax")] impl Group4Reader { pub fn new( dimensions: (u32, u32), reader: R, compressed_length: u64, fill_order: u16, ) -> crate::TiffResult { let width = u16::try_from(dimensions.0)?; let height = dimensions.1; Ok(Self { decoder: fax34::decoder::Group4Decoder::new( fax_byte_iter(reader, compressed_length, fill_order), width, )?, line_buf: io::Cursor::new(Vec::with_capacity(width.into())), width, height, y: 0, }) } } #[cfg(feature = "fax")] impl Read for Group4Reader { fn read(&mut self, buf: &mut [u8]) -> io::Result { // Either we have not read any line or we are at the end of a line. if self.line_buf.position() as usize == self.line_buf.get_ref().len() && self.y < self.height { let next = self.decoder.advance().map_err(std::io::Error::other)?; match next { fax34::decoder::DecodeStatus::End => (), fax34::decoder::DecodeStatus::Incomplete => { self.y += 1; // We known `transitions` yields exactly `self.width` items (per doc). // FIXME: performance. We do not need an individual pixel iterator, filling // memory especially for long runs can be much quicker. The `transitions` are // the positions at which each run-length ends, i.e. the prefix sum of run // lengths. Runs in fax4 start with white. let transitions = fax34::decoder::pels(self.decoder.transition(), self.width); let buffer = self.line_buf.get_mut(); buffer.resize(usize::from(self.width).div_ceil(8), 0u8); let target = &mut buffer[..]; // Note: it may seem strange to treat black as 0b1 and white as 0b0 despite all // our streams by default decoding as-if PhotometricInterpretation::BlackIsMin. // This is however consistent with libtiff. It seems that fax4's "White" // differs from what libtiff thinks of as "White". For content, a line of data // is in runlength encoding of white-black-white-black always starting with // white. In libtiff, the loop always does both colors in one go and the // structure is: // // ``` // for (; runs < erun; runs += 2) // // white run // do { *lp++ = 0L; } while (…) // // black run // do { *lp++ = -1L; } while (…) // ``` // // So indeed the Fax4::White run is implemented by filling with zeros. let mut bits = transitions.map(|c| match c { fax34::Color::Black => true, fax34::Color::White => false, }); // Assemble bits in MSB as per our library representation for buffer. for byte in target { let mut val = 0; for (idx, bit) in bits.by_ref().take(8).enumerate() { val |= u8::from(bit) << (7 - idx % 8); } *byte = val; } self.line_buf.set_position(0); } } } self.line_buf.read(buf) } } /// Owning byte reader for Group 3 decoding: the compressed data is consumed /// into an iterator so the reader doesn't borrow the buffer. #[cfg(feature = "fax")] type OwnedBitReader = fax34::ByteReader< core::iter::Map, fn(u8) -> Result>, >; /// Decodes CCITT Group 3 (T.4) 1D compressed data line by line. /// /// The fax crate's `Group3Decoder` has a bug where `new()` doesn't consume the /// initial EOL marker, causing its lookup tables to destructively consume bits /// from the EOL when trying to decode run-length codes. We work around this by /// using the crate's lower-level `white::decode` / `black::decode` functions /// and handling EOL markers ourselves. #[cfg(feature = "fax")] pub struct Group3Reader { reader: OwnedBitReader, line_buf: io::Cursor>, height: u32, width: u16, y: u32, } #[cfg(feature = "fax")] impl Group3Reader { pub fn new( dimensions: (u32, u32), reader: R, compressed_length: u64, fill_order: u16, ) -> crate::TiffResult { let width = u16::try_from(dimensions.0)?; let height = dimensions.1; // Buffer all compressed data and apply FillOrder bit reversal let mut compressed = vec![0u8; compressed_length as usize]; reader.take(compressed_length).read_exact(&mut compressed)?; if fill_order == 2 { for b in &mut compressed { *b = b.reverse_bits(); } } // Create an owning bit reader (Vec consumed by into_iter, no borrow issues) let map_fn: fn(u8) -> Result = Ok; let mut bit_reader = fax34::ByteReader::new(compressed.into_iter().map(map_fn)).unwrap(); // Skip fill bits + initial EOL marker Self::skip_eol(&mut bit_reader); Ok(Self { reader: bit_reader, line_buf: io::Cursor::new(Vec::with_capacity(width.into())), width, height, y: 0, }) } /// Skip zero fill bits followed by the terminating '1' bit of an EOL code. fn skip_eol(reader: &mut impl fax34::BitReader) { while reader.peek(1) == Some(0) { let _ = reader.consume(1); } if reader.peek(1) == Some(1) { let _ = reader.consume(1); } } /// Decode a full run-length value (terminal + optional makeup codes). fn with_markup( decoder: fn(&mut R) -> Option, reader: &mut R, ) -> Option { let mut sum = 0u16; while let Some(n) = decoder(reader) { sum += n; if n < 64 { return Some(sum); } } None } } #[cfg(feature = "fax")] impl Read for Group3Reader { fn read(&mut self, buf: &mut [u8]) -> io::Result { if self.line_buf.position() as usize == self.line_buf.get_ref().len() && self.y < self.height { // Decode one line of alternating white/black run-lengths let mut transitions = Vec::new(); let mut a0 = 0u16; let mut is_white = true; loop { let run = if is_white { Self::with_markup(fax34::maps::white::decode, &mut self.reader) } else { Self::with_markup(fax34::maps::black::decode, &mut self.reader) }; match run { Some(len) => { a0 += len; transitions.push(a0); is_white = !is_white; } None => break, } } self.y += 1; // Convert transitions to packed bilevel output let bytes_per_line = usize::from(self.width).div_ceil(8); let buffer = self.line_buf.get_mut(); buffer.clear(); buffer.resize(bytes_per_line, 0u8); let pels = fax34::decoder::pels(&transitions, self.width); for (i, c) in pels.enumerate() { if c == fax34::Color::Black { buffer[i / 8] |= 1 << (7 - (i % 8)); } } self.line_buf.set_position(0); // Skip fill bits + line-ending EOL Self::skip_eol(&mut self.reader); } self.line_buf.read(buf) } } #[cfg(feature = "webp")] pub struct WebPReader { inner: Cursor>, } #[cfg(feature = "webp")] impl WebPReader { pub fn new( reader: R, compressed_length: u64, samples: u16, ) -> crate::TiffResult { let mut decoder = image_webp::WebPDecoder::new(io::BufReader::new(reader.take(compressed_length))) .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; if !(samples == 4 || (samples == 3 && !decoder.has_alpha())) { return Err(io::Error::new( io::ErrorKind::InvalidData, "bad sample count for WebP compressed data", ) .into()); } let total_bytes = samples as usize * decoder.dimensions().0 as usize * decoder.dimensions().1 as usize; let mut data = vec![0; total_bytes]; decoder .read_image(&mut data) .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; // Add a fully opaque alpha channel if needed if samples == 4 && !decoder.has_alpha() { for i in (0..(total_bytes / 4)).rev() { data[i * 4 + 3] = 255; data[i * 4 + 2] = data[i * 3 + 2]; data[i * 4 + 1] = data[i * 3 + 1]; data[i * 4] = data[i * 3]; } } Ok(Self { inner: Cursor::new(data), }) } } #[cfg(feature = "webp")] impl Read for WebPReader { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.inner.read(buf) } } #[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); } }