diff --git a/Cargo.toml b/Cargo.toml index 3b021b4..f1b411f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ exclude = ["tests/images/*", "tests/fuzz_images/*"] half = { version = "2.4.1" } quick-error = "2.0.1" -fax = { version = "0.2.2", optional = true } +fax = { version = "0.2.4", optional = true } flate2 = { version = "1.0.20", optional = true } weezl = { version = "0.1.10", optional = true } zstd = { version = "0.13", optional = true } diff --git a/src/decoder/image.rs b/src/decoder/image.rs index 868a13e..3ce9b3e 100644 --- a/src/decoder/image.rs +++ b/src/decoder/image.rs @@ -10,8 +10,6 @@ use crate::{ ColorType, Directory, TiffError, TiffFormatError, TiffResult, TiffUnsupportedError, UsageError, }; -#[cfg(feature = "fax")] -use std::collections::VecDeque; use std::io::{self, Cursor, Read, Seek}; use std::num::NonZeroUsize; use std::sync::Arc; @@ -458,68 +456,11 @@ impl Image { Box::new(Cursor::new(data)) } #[cfg(feature = "fax")] - CompressionMethod::Fax4 => { - let width = u16::try_from(dimensions.0)?; - let height = u16::try_from(dimensions.1)?; - - struct Group4Reader { - decoder: fax::decoder::Group4Decoder>, - bits: bitvec::vec::BitVec, - byte_buf: VecDeque, - y: u16, - height: u16, - width: u16, - } - - impl Read for Group4Reader { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - if self.byte_buf.is_empty() && self.y < self.height { - let next = self - .decoder - .advance() - .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?; - - match next { - fax::decoder::DecodeStatus::End => { - // eprintln!("DONE!"); - self.byte_buf.extend(self.bits.as_raw_slice()) - } - fax::decoder::DecodeStatus::Incomplete => { - self.y += 1; - // eprintln!("{:?}", self.y); - for c in - fax::decoder::pels(self.decoder.transition(), self.width) - { - self.bits.push(match c { - fax::Color::Black => true, - fax::Color::White => false, - }); - if self.bits.len() == 8 { - self.byte_buf.extend(self.bits.as_raw_slice()); - self.bits.clear() - } - } - } - } - } - // eprintln!("{:?}: {:?} / {:?}", self.y, self.byte_buf.len(), self.bits.len()); - - self.byte_buf.read(buf) - } - } - - Box::new(Group4Reader { - decoder: fax::decoder::Group4Decoder::new( - reader.take(compressed_length).bytes(), - width, - )?, - bits: bitvec::vec::BitVec::new(), - byte_buf: VecDeque::new(), - y: 0, - width: width, - height: height, - }) - } + CompressionMethod::Fax4 => Box::new(super::stream::Group4Reader::new( + dimensions, + reader, + compressed_length, + )?), method => { return Err(TiffError::UnsupportedError( TiffUnsupportedError::UnsupportedCompressionMethod(method), diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 59cd355..3e03a9d 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -547,7 +547,6 @@ fn fix_endianness(buf: &mut [u8], byte_order: ByteOrder, bit_depth: u8) { } impl Decoder { - /// Create a new decoder that decodes from the stream ```r``` pub fn new(mut r: R) -> TiffResult> { let mut endianess = Vec::with_capacity(2); (&mut r).take(2).read_to_end(&mut endianess)?; diff --git a/src/decoder/stream.rs b/src/decoder/stream.rs index c2ff0f9..fd5623f 100644 --- a/src/decoder/stream.rs +++ b/src/decoder/stream.rs @@ -1,5 +1,7 @@ //! All IO functionality needed for TIFF decoding +#[cfg(feature = "fax")] +use std::collections::VecDeque; use std::io::{self, BufRead, BufReader, Read, Seek, Take}; /// Byte order of the TIFF file. @@ -276,6 +278,71 @@ impl Read for PackBitsReader { } } +#[cfg(feature = "fax")] +pub struct Group4Reader { + decoder: fax::decoder::Group4Decoder>>, + bits: bitvec::vec::BitVec, + byte_buf: VecDeque, + height: u16, + width: u16, + y: u16, +} + +#[cfg(feature = "fax")] +impl Group4Reader { + pub fn new( + dimensions: (u32, u32), + reader: R, + compressed_length: u64, + ) -> crate::TiffResult { + let width = u16::try_from(dimensions.0)?; + let height = u16::try_from(dimensions.1)?; + + Ok(Self { + decoder: fax::decoder::Group4Decoder::new( + reader.take(compressed_length).bytes(), + width, + )?, + bits: bitvec::vec::BitVec::new(), + byte_buf: VecDeque::new(), + width: width, + height: height, + y: 0, + }) + } + + pub fn dump_bits(&mut self) -> () { + self.byte_buf.extend(self.bits.as_raw_slice()); + self.bits.clear() + } +} + +#[cfg(feature = "fax")] +impl Read for Group4Reader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + if self.byte_buf.is_empty() && self.y < self.height { + let next = self + .decoder + .advance() + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?; + match next { + fax::decoder::DecodeStatus::End => self.dump_bits(), + fax::decoder::DecodeStatus::Incomplete => { + self.y += 1; + for c in fax::decoder::pels(self.decoder.transition(), self.width) { + self.bits.push(match c { + fax::Color::Black => true, + fax::Color::White => false, + }); + } + self.dump_bits(); + } + } + } + self.byte_buf.read(buf) + } +} + #[cfg(test)] mod test { use super::*; diff --git a/tests/decode_images.rs b/tests/decode_images.rs index 1cb7b7c..2ebe4fc 100644 --- a/tests/decode_images.rs +++ b/tests/decode_images.rs @@ -676,5 +676,5 @@ fn bytes_gray_f32() { #[test] #[cfg(feature = "fax")] fn test_fax4() { - test_image_sum_u8("fax4.tiff", ColorType::Gray(1), 62384985); + test_image_sum_u8("fax4.tiff", ColorType::Gray(1), 7802706); }