diff --git a/benches/lzw.rs b/benches/lzw.rs index 96e3d70..fce7441 100644 --- a/benches/lzw.rs +++ b/benches/lzw.rs @@ -1,7 +1,9 @@ extern crate criterion; extern crate tiff; -use criterion::{black_box, BenchmarkId, BenchmarkGroup, Criterion, Throughput, measurement::Measurement}; +use criterion::{ + black_box, measurement::Measurement, BenchmarkGroup, BenchmarkId, Criterion, Throughput, +}; use tiff::decoder::Decoder; fn read_image(image: &[u8]) { @@ -29,9 +31,7 @@ fn main() { .bench_with_input( BenchmarkId::new(def.id, def.data.len()), def.data, - |b, input| { - b.iter(|| read_image(input)) - } + |b, input| b.iter(|| read_image(input)), ); }; @@ -46,27 +46,51 @@ fn main() { }); */ - run_bench_def(&mut group, BenchDef { - data: include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/images/issue_69_lzw.tiff")), - id: "issue-69-lzw.tif", - sample_size: 500, - }); + run_bench_def( + &mut group, + BenchDef { + data: include_bytes!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/tests/images/issue_69_lzw.tiff" + )), + id: "issue-69-lzw.tif", + sample_size: 500, + }, + ); - run_bench_def(&mut group, BenchDef { - data: include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/benches/kodim02-lzw.tif")), - id: "kodim02-lzw.tif", - sample_size: 20, - }); + run_bench_def( + &mut group, + BenchDef { + data: include_bytes!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/tests/benches/kodim02-lzw.tif" + )), + id: "kodim02-lzw.tif", + sample_size: 20, + }, + ); - run_bench_def(&mut group, BenchDef { - data: include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/benches/kodim07-lzw.tif")), - id: "kodim07-lzw.tif", - sample_size: 20, - }); + run_bench_def( + &mut group, + BenchDef { + data: include_bytes!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/tests/benches/kodim07-lzw.tif" + )), + id: "kodim07-lzw.tif", + sample_size: 20, + }, + ); - run_bench_def(&mut group, BenchDef { - data: include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/benches/Transparency-lzw.tif")), - id: "Transparency-lzw.tif", - sample_size: 20, - }); + run_bench_def( + &mut group, + BenchDef { + data: include_bytes!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/tests/benches/Transparency-lzw.tif" + )), + id: "Transparency-lzw.tif", + sample_size: 20, + }, + ); } diff --git a/src/decoder/ifd.rs b/src/decoder/ifd.rs index 8667299..d11319b 100644 --- a/src/decoder/ifd.rs +++ b/src/decoder/ifd.rs @@ -1,7 +1,7 @@ //! Function for reading TIFF tags use std::collections::HashMap; -use std::convert::{TryInto, TryFrom}; +use std::convert::{TryFrom, TryInto}; use std::io::{self, Read, Seek}; use std::mem; @@ -9,8 +9,10 @@ use super::stream::{ByteOrder, EndianReader, SmartReader}; use tags::{Tag, Type}; use {TiffError, TiffFormatError, TiffResult, TiffUnsupportedError}; -use self::Value::{Ascii, List, Float, Double, Rational, Unsigned, Signed, SRational, RationalBig, UnsignedBig, SignedBig, SRationalBig}; - +use self::Value::{ + Ascii, Double, Float, List, Rational, RationalBig, SRational, SRationalBig, Signed, SignedBig, + Unsigned, UnsignedBig, +}; #[allow(unused_qualifications)] #[derive(Debug, Clone, PartialEq)] @@ -102,7 +104,9 @@ impl Value { Unsigned(val) => Ok(vec![val]), UnsignedBig(val) => Ok(vec![u32::try_from(val)?]), Rational(numerator, denominator) => Ok(vec![numerator, denominator]), - RationalBig(numerator, denominator) => Ok(vec![u32::try_from(numerator)?, u32::try_from(denominator)?]), + RationalBig(numerator, denominator) => { + Ok(vec![u32::try_from(numerator)?, u32::try_from(denominator)?]) + } Ascii(val) => Ok(val.chars().map(u32::from).collect()), val => Err(TiffError::FormatError( TiffFormatError::UnsignedIntegerExpected(val), @@ -132,7 +136,9 @@ impl Value { Signed(val) => Ok(vec![val]), SignedBig(val) => Ok(vec![i32::try_from(val)?]), SRational(numerator, denominator) => Ok(vec![numerator, denominator]), - SRationalBig(numerator, denominator) => Ok(vec![i32::try_from(numerator)?, i32::try_from(denominator)?]), + SRationalBig(numerator, denominator) => { + Ok(vec![i32::try_from(numerator)?, i32::try_from(denominator)?]) + } val => Err(TiffError::FormatError( TiffFormatError::SignedIntegerExpected(val), )), @@ -220,7 +226,7 @@ impl Value { } } } - + #[derive(Clone)] pub struct Entry { type_: Type, @@ -309,17 +315,11 @@ impl Entry { } (Type::LONG, 2) => { let mut r = self.r(bo); - Some(List(vec![ - Unsigned(r.read_u32()?), - Unsigned(r.read_u32()?), - ])) + Some(List(vec![Unsigned(r.read_u32()?), Unsigned(r.read_u32()?)])) } (Type::SLONG, 2) => { let mut r = self.r(bo); - Some(List(vec![ - Signed(r.read_i32()?), - Signed(r.read_i32()?), - ])) + Some(List(vec![Signed(r.read_i32()?), Signed(r.read_i32()?)])) } (Type::RATIONAL, 1) => { let mut r = self.r(bo); @@ -333,7 +333,7 @@ impl Entry { let denominator = r.read_i32()?; Some(SRational(numerator, denominator)) } - _ => None + _ => None, } } else { None @@ -409,10 +409,10 @@ impl Entry { if n > limits.decoding_buffer_size { return Err(TiffError::LimitsExceeded); } - + if (n <= 4 && !decoder.bigtiff) || (n <= 8 && decoder.bigtiff) { let mut buf = vec![0; n]; - self.r(bo).read_exact(&mut buf )?; + self.r(bo).read_exact(&mut buf)?; let v = String::from_utf8(buf)?; let v = v.trim_matches(char::from(0)); Ok(Ascii(v.into())) @@ -434,10 +434,17 @@ impl Entry { } #[inline] - fn decode_offset(&self, value_count: u64, bo: ByteOrder, limits: &super::Limits, decoder: &mut super::Decoder, decode_fn: F) -> TiffResult - where - R: Read + Seek, - F: Fn(&mut super::Decoder) -> TiffResult, + fn decode_offset( + &self, + value_count: u64, + bo: ByteOrder, + limits: &super::Limits, + decoder: &mut super::Decoder, + decode_fn: F, + ) -> TiffResult + where + R: Read + Seek, + F: Fn(&mut super::Decoder) -> TiffResult, { let value_count = usize::try_from(value_count)?; if value_count > limits.decoding_buffer_size / mem::size_of::() { @@ -464,7 +471,7 @@ fn offset_to_bytes(n: usize, entry: &Entry) -> TiffResult { entry.offset[0..n] .iter() .map(|&e| Unsigned(u32::from(e))) - .collect() + .collect(), )) } @@ -475,7 +482,7 @@ fn offset_to_sbytes(n: usize, entry: &Entry) -> TiffResult { entry.offset[0..n] .iter() .map(|&e| Signed(i32::from(e as i8))) - .collect() + .collect(), )) } diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index fcb1736..5ed079f 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -1,14 +1,16 @@ -use std::convert::TryFrom; -use std::collections::HashMap; -use std::io::{self, Read, Seek}; use std::cmp; +use std::collections::HashMap; +use std::convert::TryFrom; +use std::io::{self, Read, Seek}; use {ColorType, TiffError, TiffFormatError, TiffResult, TiffUnsupportedError}; use self::ifd::Directory; use tags::{CompressionMethod, PhotometricInterpretation, Predictor, SampleFormat, Tag, Type}; -use self::stream::{ByteOrder, EndianReader, LZWReader, DeflateReader, PackBitsReader, SmartReader}; +use self::stream::{ + ByteOrder, DeflateReader, EndianReader, LZWReader, PackBitsReader, SmartReader, +}; pub mod ifd; mod stream; @@ -263,8 +265,14 @@ fn rev_hpredict(image: DecodingBuffer, size: (u32, u32), color_type: ColorType) let samples = match color_type { ColorType::Gray(8) | ColorType::Gray(16) | ColorType::Gray(32) | ColorType::Gray(64) => 1, ColorType::RGB(8) | ColorType::RGB(16) | ColorType::RGB(32) | ColorType::RGB(64) => 3, - ColorType::RGBA(8) | ColorType::RGBA(16) | ColorType::RGBA(32) | ColorType::RGBA(64) - | ColorType::CMYK(8) | ColorType::CMYK(16) | ColorType::CMYK(32) | ColorType::CMYK(64) => 4, + ColorType::RGBA(8) + | ColorType::RGBA(16) + | ColorType::RGBA(32) + | ColorType::RGBA(64) + | ColorType::CMYK(8) + | ColorType::CMYK(16) + | ColorType::CMYK(32) + | ColorType::CMYK(64) => 4, _ => { return Err(TiffError::UnsupportedError( TiffUnsupportedError::HorizontalPredictor(color_type), @@ -289,7 +297,7 @@ fn rev_hpredict(image: DecodingBuffer, size: (u32, u32), color_type: ColorType) // See issue #89. // rev_hpredict_nsamp(buf, size, samples)?; return Err(TiffError::UnsupportedError( - TiffUnsupportedError::HorizontalPredictor(color_type) + TiffUnsupportedError::HorizontalPredictor(color_type), )); } DecodingBuffer::F64(_buf) => { @@ -297,7 +305,7 @@ fn rev_hpredict(image: DecodingBuffer, size: (u32, u32), color_type: ColorType) // See issue #89. // rev_hpredict_nsamp(buf, size, samples)?; return Err(TiffError::UnsupportedError( - TiffUnsupportedError::HorizontalPredictor(color_type) + TiffUnsupportedError::HorizontalPredictor(color_type), )); } } @@ -337,28 +345,24 @@ impl Decoder { pub fn colortype(&mut self) -> TiffResult { match self.photometric_interpretation { - PhotometricInterpretation::RGB => { - match self.bits_per_sample[..] { - [r, g, b] if [r, r] == [g, b] => Ok(ColorType::RGB(r)), - [r, g, b, a] if [r, r, r] == [g, b, a] => Ok(ColorType::RGBA(r)), - _ => Err(TiffError::UnsupportedError( - TiffUnsupportedError::InterpretationWithBits( - self.photometric_interpretation, - self.bits_per_sample.clone(), - ), - )), - } + PhotometricInterpretation::RGB => match self.bits_per_sample[..] { + [r, g, b] if [r, r] == [g, b] => Ok(ColorType::RGB(r)), + [r, g, b, a] if [r, r, r] == [g, b, a] => Ok(ColorType::RGBA(r)), + _ => Err(TiffError::UnsupportedError( + TiffUnsupportedError::InterpretationWithBits( + self.photometric_interpretation, + self.bits_per_sample.clone(), + ), + )), }, - PhotometricInterpretation::CMYK => { - match self.bits_per_sample[..] { - [c, m, y, k] if [c, c, c] == [m, y, k] => Ok(ColorType::CMYK(c)), - _ => Err(TiffError::UnsupportedError( - TiffUnsupportedError::InterpretationWithBits( - self.photometric_interpretation, - self.bits_per_sample.clone(), - ), - )), - } + PhotometricInterpretation::CMYK => match self.bits_per_sample[..] { + [c, m, y, k] if [c, c, c] == [m, y, k] => Ok(ColorType::CMYK(c)), + _ => Err(TiffError::UnsupportedError( + TiffUnsupportedError::InterpretationWithBits( + self.photometric_interpretation, + self.bits_per_sample.clone(), + ), + )), }, PhotometricInterpretation::BlackIsZero | PhotometricInterpretation::WhiteIsZero if self.bits_per_sample.len() == 1 => @@ -402,18 +406,20 @@ impl Decoder { if self.read_short()? != 8 { return Err(TiffError::FormatError( TiffFormatError::TiffSignatureNotFound, - )) + )); } // This constant should always be 0 if self.read_short()? != 0 { return Err(TiffError::FormatError( TiffFormatError::TiffSignatureNotFound, - )) + )); } - }, - _ => return Err(TiffError::FormatError( - TiffFormatError::TiffSignatureInvalid, - )) + } + _ => { + return Err(TiffError::FormatError( + TiffFormatError::TiffSignatureInvalid, + )) + } } self.next_ifd = match self.read_ifd_offset()? { 0 => None, @@ -451,19 +457,25 @@ impl Decoder { self.samples = val; } if let Some(vals) = self.find_tag_unsigned_vec(Tag::SampleFormat)? { - self.sample_format = vals.into_iter() + self.sample_format = vals + .into_iter() .map(SampleFormat::from_u16_exhaustive) .collect(); // TODO: for now, only homogenous formats across samples are supported. if !self.sample_format.windows(2).all(|s| s[0] == s[1]) { - return Err(TiffUnsupportedError::UnsupportedSampleFormat(self.sample_format.clone()).into()) + return Err(TiffUnsupportedError::UnsupportedSampleFormat( + self.sample_format.clone(), + ) + .into()); } } match self.samples { - 1 | 3 | 4 => if let Some(val) = self.find_tag_unsigned_vec(Tag::BitsPerSample)? { - self.bits_per_sample = val; - }, + 1 | 3 | 4 => { + if let Some(val) = self.find_tag_unsigned_vec(Tag::BitsPerSample)? { + self.bits_per_sample = val; + } + } _ => return Err(TiffUnsupportedError::UnsupportedSampleDepth(self.samples).into()), } Ok(()) @@ -553,7 +565,9 @@ impl Decoder { #[inline] pub fn read_offset(&mut self) -> TiffResult<[u8; 4]> { if self.bigtiff { - return Err(TiffError::FormatError(TiffFormatError::InconsistentSizesEncountered)) + return Err(TiffError::FormatError( + TiffFormatError::InconsistentSizesEncountered, + )); } let mut val = [0; 4]; self.reader.read_exact(&mut val)?; @@ -576,9 +590,7 @@ impl Decoder { #[inline] pub fn goto_offset_u64(&mut self, offset: u64) -> io::Result<()> { - self.reader - .seek(io::SeekFrom::Start(offset)) - .map(|_| ()) + self.reader.seek(io::SeekFrom::Start(offset)).map(|_| ()) } /// Reads a IFD entry. @@ -600,22 +612,11 @@ impl Decoder { } }; let entry = if self.bigtiff { - ifd::Entry::new_u64( - type_, - self.read_long8()?, - self.read_offset_u64()? - ) + ifd::Entry::new_u64(type_, self.read_long8()?, self.read_offset_u64()?) } else { - ifd::Entry::new( - type_, - self.read_long()?, - self.read_offset()? - ) + ifd::Entry::new(type_, self.read_long()?, self.read_offset()?) }; - Ok(Some(( - tag, - entry, - ))) + Ok(Some((tag, entry))) } /// Reads the next IFD @@ -629,7 +630,11 @@ impl Decoder { } Some(offset) => self.goto_offset_u64(offset)?, } - let num_tags = if self.bigtiff { self.read_long8()? } else { self.read_short()?.into() }; + let num_tags = if self.bigtiff { + self.read_long8()? + } else { + self.read_short()?.into() + }; for _ in 0..num_tags { let (tag, entry) = match self.read_entry()? { Some(val) => val, @@ -660,20 +665,30 @@ impl Decoder { /// Tries to retrieve a tag and convert it to the desired unsigned type. pub fn find_tag_unsigned>(&mut self, tag: Tag) -> TiffResult> { self.find_tag(tag)? - .map(|v| v.into_u64()).transpose()? - .map(|value| T::try_from(value) - .map_err(|_| TiffFormatError::InvalidTagValueType(tag).into())) + .map(|v| v.into_u64()) + .transpose()? + .map(|value| { + T::try_from(value).map_err(|_| TiffFormatError::InvalidTagValueType(tag).into()) + }) .transpose() } /// Tries to retrieve a vector of all a tag's values and convert them to /// the desired unsigned type. - pub fn find_tag_unsigned_vec>(&mut self, tag: Tag) -> TiffResult>> { + pub fn find_tag_unsigned_vec>( + &mut self, + tag: Tag, + ) -> TiffResult>> { self.find_tag(tag)? - .map(|v| v.into_u64_vec()).transpose()? - .map(|v| v.into_iter() - .map(|u| T::try_from(u).map_err(|_| TiffFormatError::InvalidTagValueType(tag).into())) - .collect()) + .map(|v| v.into_u64_vec()) + .transpose()? + .map(|v| { + v.into_iter() + .map(|u| { + T::try_from(u).map_err(|_| TiffFormatError::InvalidTagValueType(tag).into()) + }) + .collect() + }) .transpose() } @@ -754,21 +769,19 @@ impl Decoder { let (bytes, reader) = LZWReader::new( &mut self.reader, usize::try_from(length)?, - max_uncompressed_length * buffer.byte_len() + max_uncompressed_length * buffer.byte_len(), )?; (bytes, Box::new(reader)) } CompressionMethod::PackBits => { let order = self.reader.byte_order; - let (bytes, reader) = PackBitsReader::new( - &mut self.reader, - order, - usize::try_from(length)?, - )?; + let (bytes, reader) = + PackBitsReader::new(&mut self.reader, order, usize::try_from(length)?)?; (bytes, Box::new(reader)) } CompressionMethod::OldDeflate => { - let (bytes, reader) = DeflateReader::new(&mut self.reader, max_uncompressed_length)?; + let (bytes, reader) = + DeflateReader::new(&mut self.reader, max_uncompressed_length)?; (bytes, Box::new(reader)) } method => { @@ -887,9 +900,7 @@ impl Decoder { /// Number of strips in image pub fn strip_count(&mut self) -> TiffResult { - let rows_per_strip = self - .get_tag_u32(Tag::RowsPerStrip) - .unwrap_or(self.height); + let rows_per_strip = self.get_tag_u32(Tag::RowsPerStrip).unwrap_or(self.height); if rows_per_strip == 0 { return Ok(0); @@ -935,9 +946,8 @@ impl Decoder { TiffFormatError::InconsistentSizesEncountered, ))?; - let rows_per_strip = usize::try_from(self - .get_tag_u32(Tag::RowsPerStrip) - .unwrap_or(self.height))?; + let rows_per_strip = + usize::try_from(self.get_tag_u32(Tag::RowsPerStrip).unwrap_or(self.height))?; let strip_height = cmp::min( rows_per_strip, @@ -996,22 +1006,20 @@ impl Decoder { n if n <= 16 => DecodingResult::new_u16(buffer_size, &self.limits), n if n <= 32 => DecodingResult::new_u32(buffer_size, &self.limits), n if n <= 64 => DecodingResult::new_u64(buffer_size, &self.limits), - n => { - Err(TiffError::UnsupportedError( - TiffUnsupportedError::UnsupportedBitsPerChannel(n), - )) - } + n => Err(TiffError::UnsupportedError( + TiffUnsupportedError::UnsupportedBitsPerChannel(n), + )), }, SampleFormat::IEEEFP => match max_sample_bits { 32 => DecodingResult::new_f32(buffer_size, &self.limits), 64 => DecodingResult::new_f64(buffer_size, &self.limits), - n => { - Err(TiffError::UnsupportedError( - TiffUnsupportedError::UnsupportedBitsPerChannel(n), - )) - } + n => Err(TiffError::UnsupportedError( + TiffUnsupportedError::UnsupportedBitsPerChannel(n), + )), }, - format => Err(TiffUnsupportedError::UnsupportedSampleFormat(vec![format.clone()]).into()), + format => { + Err(TiffUnsupportedError::UnsupportedSampleFormat(vec![format.clone()]).into()) + } } } @@ -1020,9 +1028,8 @@ impl Decoder { self.initialize_strip_decoder()?; let index = self.strip_decoder.as_ref().unwrap().strip_index; - let rows_per_strip = usize::try_from(self - .get_tag_u32(Tag::RowsPerStrip) - .unwrap_or(self.height))?; + let rows_per_strip = + usize::try_from(self.get_tag_u32(Tag::RowsPerStrip).unwrap_or(self.height))?; let strip_height = cmp::min( rows_per_strip, @@ -1039,9 +1046,8 @@ impl Decoder { /// Decodes the entire image and return it as a Vector pub fn read_image(&mut self) -> TiffResult { self.initialize_strip_decoder()?; - let rows_per_strip = usize::try_from(self - .get_tag_u32(Tag::RowsPerStrip) - .unwrap_or(self.height))?; + let rows_per_strip = + usize::try_from(self.get_tag_u32(Tag::RowsPerStrip).unwrap_or(self.height))?; let samples_per_strip = usize::try_from(self.width)? * rows_per_strip * self.bits_per_sample.len(); diff --git a/src/decoder/stream.rs b/src/decoder/stream.rs index dbdf300..7c7affd 100644 --- a/src/decoder/stream.rs +++ b/src/decoder/stream.rs @@ -34,14 +34,16 @@ pub trait EndianReader: Read { fn read_u16_into(&mut self, buffer: &mut [u16]) -> Result<(), io::Error> { self.read_exact(bytecast::u16_as_ne_mut_bytes(buffer))?; match self.byte_order() { - ByteOrder::LittleEndian => + ByteOrder::LittleEndian => { for n in buffer { *n = u16::from_le(*n); - }, - ByteOrder::BigEndian => + } + } + ByteOrder::BigEndian => { for n in buffer { *n = u16::from_be(*n); - }, + } + } } Ok(()) } @@ -72,14 +74,16 @@ pub trait EndianReader: Read { fn read_u32_into(&mut self, buffer: &mut [u32]) -> Result<(), io::Error> { self.read_exact(bytecast::u32_as_ne_mut_bytes(buffer))?; match self.byte_order() { - ByteOrder::LittleEndian => + ByteOrder::LittleEndian => { for n in buffer { *n = u32::from_le(*n); - }, - ByteOrder::BigEndian => + } + } + ByteOrder::BigEndian => { for n in buffer { *n = u32::from_be(*n); - }, + } + } } Ok(()) } @@ -110,14 +114,16 @@ pub trait EndianReader: Read { fn read_u64_into(&mut self, buffer: &mut [u64]) -> Result<(), io::Error> { self.read_exact(bytecast::u64_as_ne_mut_bytes(buffer))?; match self.byte_order() { - ByteOrder::LittleEndian => + ByteOrder::LittleEndian => { for n in buffer { *n = u64::from_le(*n); - }, - ByteOrder::BigEndian => + } + } + ByteOrder::BigEndian => { for n in buffer { *n = u64::from_be(*n); - }, + } + } } Ok(()) } @@ -137,14 +143,16 @@ pub trait EndianReader: Read { fn read_f32_into(&mut self, buffer: &mut [f32]) -> Result<(), io::Error> { self.read_exact(bytecast::f32_as_ne_mut_bytes(buffer))?; match self.byte_order() { - ByteOrder::LittleEndian => + ByteOrder::LittleEndian => { for n in buffer { *n = f32::from_bits(u32::from_le(n.to_bits())); - }, - ByteOrder::BigEndian => + } + } + ByteOrder::BigEndian => { for n in buffer { *n = f32::from_bits(u32::from_be(n.to_bits())); - }, + } + } } Ok(()) } @@ -164,14 +172,16 @@ pub trait EndianReader: Read { fn read_f64_into(&mut self, buffer: &mut [f64]) -> Result<(), io::Error> { self.read_exact(bytecast::f64_as_ne_mut_bytes(buffer))?; match self.byte_order() { - ByteOrder::LittleEndian => + ByteOrder::LittleEndian => { for n in buffer { *n = f64::from_bits(u64::from_le(n.to_bits())); - }, - ByteOrder::BigEndian => + } + } + ByteOrder::BigEndian => { for n in buffer { *n = f64::from_bits(u64::from_be(n.to_bits())); - }, + } + } } Ok(()) } @@ -251,17 +261,22 @@ impl LZWReader { let buffer_space = uncompressed.capacity(); uncompressed.resize(buffer_space, 0u8); - let result = decoder.decode_bytes(&compressed[bytes_read..], &mut uncompressed[bytes_written..]); + let result = decoder.decode_bytes( + &compressed[bytes_read..], + &mut uncompressed[bytes_written..], + ); bytes_read += result.consumed_in; uncompressed.truncate(bytes_written + result.consumed_out); match result.status { - Ok(weezl::LzwStatus::Ok) => {}, + Ok(weezl::LzwStatus::Ok) => {} Ok(weezl::LzwStatus::Done) => break, - Ok(weezl::LzwStatus::NoProgress) => return Err(io::Error::new( - io::ErrorKind::UnexpectedEof, - "no lzw end code found", - )), + Ok(weezl::LzwStatus::NoProgress) => { + return Err(io::Error::new( + io::ErrorKind::UnexpectedEof, + "no lzw end code found", + )) + } Err(err) => return Err(io::Error::new(io::ErrorKind::InvalidData, err)), } } diff --git a/src/encoder/mod.rs b/src/encoder/mod.rs index 63c52b5..8339718 100644 --- a/src/encoder/mod.rs +++ b/src/encoder/mod.rs @@ -4,8 +4,8 @@ use std::io::{Seek, Write}; use std::mem; use bytecast; -use tags::{self, ResolutionUnit, Tag, Type}; use error::{TiffError, TiffFormatError, TiffResult}; +use tags::{self, ResolutionUnit, Tag, Type}; pub mod colortype; mod writer; @@ -495,8 +495,10 @@ impl<'a, W: 'a + Write + Seek> DirectoryEncoder<'a, W> { value.write(&mut writer)?; } - self.ifd - .insert(tag.to_u16(), (::FIELD_TYPE.to_u16(), value.count(), bytes)); + self.ifd.insert( + tag.to_u16(), + (::FIELD_TYPE.to_u16(), value.count(), bytes), + ); Ok(()) } @@ -636,7 +638,10 @@ impl<'a, W: 'a + Write + Seek, T: ColorType> ImageEncoder<'a, W, T> { encoder.write_tag(Tag::RowsPerStrip, u32::try_from(rows_per_strip)?)?; - encoder.write_tag(Tag::SamplesPerPixel, u16::try_from(::BITS_PER_SAMPLE.len())?)?; + encoder.write_tag( + Tag::SamplesPerPixel, + u16::try_from(::BITS_PER_SAMPLE.len())?, + )?; encoder.write_tag(Tag::XResolution, Rational { n: 1, d: 1 })?; encoder.write_tag(Tag::YResolution, Rational { n: 1, d: 1 })?; encoder.write_tag(Tag::ResolutionUnit, ResolutionUnit::None.to_u16())?; @@ -662,7 +667,8 @@ impl<'a, W: 'a + Write + Seek, T: ColorType> ImageEncoder<'a, W, T> { return 0; } - let start_row = ::std::cmp::min(u64::from(self.height), self.strip_idx * self.rows_per_strip); + let start_row = + ::std::cmp::min(u64::from(self.height), self.strip_idx * self.rows_per_strip); let end_row = ::std::cmp::min( u64::from(self.height), (self.strip_idx + 1) * self.rows_per_strip, @@ -681,7 +687,9 @@ impl<'a, W: 'a + Write + Seek, T: ColorType> ImageEncoder<'a, W, T> { if u64::try_from(value.len())? != samples { return Err(::std::io::Error::new( ::std::io::ErrorKind::InvalidData, - "Slice is wrong size for strip").into()); + "Slice is wrong size for strip", + ) + .into()); } let offset = self.encoder.write_data(value)?; @@ -697,14 +705,20 @@ impl<'a, W: 'a + Write + Seek, T: ColorType> ImageEncoder<'a, W, T> { where [T::Inner]: TiffValue, { - let num_pix = usize::try_from(self.width)?.checked_mul(usize::try_from(self.height)?) - .ok_or_else(|| ::std::io::Error::new( - ::std::io::ErrorKind::InvalidInput, - "Image width * height exceeds usize"))?; + let num_pix = usize::try_from(self.width)? + .checked_mul(usize::try_from(self.height)?) + .ok_or_else(|| { + ::std::io::Error::new( + ::std::io::ErrorKind::InvalidInput, + "Image width * height exceeds usize", + ) + })?; if data.len() < num_pix { return Err(::std::io::Error::new( ::std::io::ErrorKind::InvalidData, - "Input data slice is undersized for provided dimensions").into()); + "Input data slice is undersized for provided dimensions", + ) + .into()); } let mut idx = 0; while self.next_strip_sample_count() > 0 { @@ -718,14 +732,20 @@ impl<'a, W: 'a + Write + Seek, T: ColorType> ImageEncoder<'a, W, T> { /// Set image resolution pub fn resolution(&mut self, unit: ResolutionUnit, value: Rational) { - self.encoder.write_tag(Tag::ResolutionUnit, unit.to_u16()).unwrap(); - self.encoder.write_tag(Tag::XResolution, value.clone()).unwrap(); + self.encoder + .write_tag(Tag::ResolutionUnit, unit.to_u16()) + .unwrap(); + self.encoder + .write_tag(Tag::XResolution, value.clone()) + .unwrap(); self.encoder.write_tag(Tag::YResolution, value).unwrap(); } /// Set image resolution unit pub fn resolution_unit(&mut self, unit: ResolutionUnit) { - self.encoder.write_tag(Tag::ResolutionUnit, unit.to_u16()).unwrap(); + self.encoder + .write_tag(Tag::ResolutionUnit, unit.to_u16()) + .unwrap(); } /// Set image x-resolution diff --git a/src/error.rs b/src/error.rs index 32f50bf..5ace43c 100644 --- a/src/error.rs +++ b/src/error.rs @@ -3,9 +3,9 @@ use std::fmt; use std::io; use std::string; -use decoder::ifd::{Value}; -use tags::{CompressionMethod, PhotometricInterpretation, PlanarConfiguration, SampleFormat, Tag}; +use decoder::ifd::Value; use miniz_oxide::inflate::TINFLStatus; +use tags::{CompressionMethod, PhotometricInterpretation, PlanarConfiguration, SampleFormat, Tag}; use ColorType; /// Tiff error kinds. @@ -62,8 +62,9 @@ impl fmt::Display for TiffFormatError { ImageFileDirectoryNotFound => write!(fmt, "Image file directory not found."), InconsistentSizesEncountered => write!(fmt, "Inconsistent sizes encountered."), InvalidTag => write!(fmt, "Image contains invalid tag."), - InvalidTagValueType(ref tag) => - write!(fmt, "Tag `{:?}` did not have the expected value type.", tag), + InvalidTagValueType(ref tag) => { + write!(fmt, "Tag `{:?}` did not have the expected value type.", tag) + } RequiredTagNotFound(ref tag) => write!(fmt, "Required tag `{:?}` not found.", tag), UnknownPredictor(ref predictor) => { write!(fmt, "Unknown predictor “{}” encountered", predictor) diff --git a/src/lib.rs b/src/lib.rs index c3f80dc..f9346cb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,8 +6,8 @@ //! # Related Links //! * - The TIFF specification -extern crate weezl; extern crate miniz_oxide; +extern crate weezl; mod bytecast; pub mod decoder; diff --git a/src/tags.rs b/src/tags.rs index fb96a5d..d28808a 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -140,7 +140,6 @@ pub enum Type(u16) { } } - tags! { pub enum CompressionMethod(u16) { None = 1, @@ -182,7 +181,7 @@ pub enum Predictor(u16) { } } -tags!{ +tags! { /// Type to represent resolution units pub enum ResolutionUnit(u16) { None = 1, @@ -198,4 +197,4 @@ pub enum SampleFormat(u16) unknown("An unknown extension sample format") { IEEEFP = 3, Void = 4, } -} \ No newline at end of file +} diff --git a/tests/decode_images.rs b/tests/decode_images.rs index 90d77ac..2336178 100644 --- a/tests/decode_images.rs +++ b/tests/decode_images.rs @@ -21,7 +21,7 @@ macro_rules! test_image_sum { DecodingResult::$buffer(res) => { let sum: $sum_ty = res.into_iter().map(<$sum_ty>::from).sum(); assert_eq!(sum, expected_sum); - }, + } _ => panic!("Wrong bit depth"), } } @@ -44,7 +44,9 @@ fn test_image_color_type_unsupported(file: &str, expected_type: ColorType) { let mut decoder = Decoder::new(img_file).expect("Cannot create decoder"); assert_eq!(decoder.colortype().unwrap(), expected_type); assert!(match decoder.read_image() { - Err(tiff::TiffError::UnsupportedError(tiff::TiffUnsupportedError::UnsupportedColorType(_))) => true, + Err(tiff::TiffError::UnsupportedError( + tiff::TiffUnsupportedError::UnsupportedColorType(_), + )) => true, _ => false, }); } @@ -96,7 +98,11 @@ fn test_gray_f32() { #[test] fn test_gray_f64() { - test_image_sum_f64("gradient-1c-64b-float.tiff", ColorType::Gray(64), 128.0319210877642); + test_image_sum_f64( + "gradient-1c-64b-float.tiff", + ColorType::Gray(64), + 128.0319210877642, + ); } #[test] diff --git a/tests/encode_images.rs b/tests/encode_images.rs index f122501..e5c6a8c 100644 --- a/tests/encode_images.rs +++ b/tests/encode_images.rs @@ -1,9 +1,9 @@ extern crate tiff; -use tiff::decoder::{Decoder, DecodingResult, ifd}; -use tiff::encoder::{colortype, TiffEncoder, SRational}; -use tiff::ColorType; +use tiff::decoder::{ifd, Decoder, DecodingResult}; +use tiff::encoder::{colortype, SRational, TiffEncoder}; use tiff::tags::Tag; +use tiff::ColorType; use std::fs::File; use std::io::{Cursor, Seek, SeekFrom}; @@ -24,18 +24,22 @@ fn encode_decode() { { let mut tiff = TiffEncoder::new(&mut file).unwrap(); - let mut image = tiff.new_image::(100, 100) + let mut image = tiff.new_image::(100, 100).unwrap(); + image + .encoder() + .write_tag(Tag::Artist, "Image-tiff") .unwrap(); - image.encoder().write_tag(Tag::Artist, "Image-tiff").unwrap(); image.write_data(&image_data).unwrap(); - } { file.seek(SeekFrom::Start(0)).unwrap(); let mut decoder = Decoder::new(&mut file).unwrap(); assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(8)); assert_eq!(decoder.dimensions().unwrap(), (100, 100)); - assert_eq!(decoder.get_tag(Tag::Artist).unwrap(), ifd::Value::Ascii("Image-tiff".into())); + assert_eq!( + decoder.get_tag(Tag::Artist).unwrap(), + ifd::Value::Ascii("Image-tiff".into()) + ); if let DecodingResult::U8(img_res) = decoder.read_image().unwrap() { assert_eq!(image_data, img_res); } else { @@ -62,7 +66,10 @@ const TEST_IMAGE_DIR: &str = "./tests/images/"; macro_rules! test_roundtrip { ($name:ident, $buffer:ident, $buffer_ty:ty) => { - fn $name>(file: &str, expected_type: ColorType) { + fn $name>( + file: &str, + expected_type: ColorType, + ) { let path = PathBuf::from(TEST_IMAGE_DIR).join(file); let img_file = File::open(path).expect("Cannot find test image!"); let mut decoder = Decoder::new(img_file).expect("Cannot create decoder"); @@ -78,8 +85,7 @@ macro_rules! test_roundtrip { let mut tiff = TiffEncoder::new(&mut file).unwrap(); let (width, height) = decoder.dimensions().unwrap(); - tiff.write_image::(width, height, &image_data) - .unwrap(); + tiff.write_image::(width, height, &image_data).unwrap(); } file.seek(SeekFrom::Start(0)).unwrap(); { @@ -183,13 +189,19 @@ impl AssertDecode for Decoder { self.get_tag(Tag::Unknown(tag)).unwrap().into_u32().unwrap() } fn assert_tag_u32_vec(&mut self, tag: u16) -> Vec { - self.get_tag(Tag::Unknown(tag)).unwrap().into_u32_vec().unwrap() + self.get_tag(Tag::Unknown(tag)) + .unwrap() + .into_u32_vec() + .unwrap() } fn assert_tag_i32(&mut self, tag: u16) -> i32 { self.get_tag(Tag::Unknown(tag)).unwrap().into_i32().unwrap() } fn assert_tag_i32_vec(&mut self, tag: u16) -> Vec { - self.get_tag(Tag::Unknown(tag)).unwrap().into_i32_vec().unwrap() + self.get_tag(Tag::Unknown(tag)) + .unwrap() + .into_i32_vec() + .unwrap() } } @@ -203,10 +215,18 @@ fn test_multiple_byte() { let encoder = image_encoder.encoder(); encoder.write_tag(Tag::Unknown(65000), &[1_u8][..]).unwrap(); - encoder.write_tag(Tag::Unknown(65001), &[1_u8, 2][..]).unwrap(); - encoder.write_tag(Tag::Unknown(65002), &[1_u8, 2, 3][..]).unwrap(); - encoder.write_tag(Tag::Unknown(65003), &[1_u8, 2, 3, 4][..]).unwrap(); - encoder.write_tag(Tag::Unknown(65004), &[1_u8, 2, 3, 4, 5][..]).unwrap(); + encoder + .write_tag(Tag::Unknown(65001), &[1_u8, 2][..]) + .unwrap(); + encoder + .write_tag(Tag::Unknown(65002), &[1_u8, 2, 3][..]) + .unwrap(); + encoder + .write_tag(Tag::Unknown(65003), &[1_u8, 2, 3, 4][..]) + .unwrap(); + encoder + .write_tag(Tag::Unknown(65004), &[1_u8, 2, 3, 4, 5][..]) + .unwrap(); } data.set_position(0); @@ -236,23 +256,48 @@ fn test_signed() { //Use the "reusable" tags section as per the TIFF6 spec encoder.write_tag(Tag::Unknown(65000), -1_i8).unwrap(); - encoder.write_tag(Tag::Unknown(65001), &[-1_i8][..]).unwrap(); - encoder.write_tag(Tag::Unknown(65002), &[-1_i8, 2][..]).unwrap(); - encoder.write_tag(Tag::Unknown(65003), &[-1_i8, 2, -3][..]).unwrap(); - encoder.write_tag(Tag::Unknown(65004), &[-1_i8, 2, -3, 4][..]).unwrap(); - encoder.write_tag(Tag::Unknown(65005), &[-1_i8, 2, -3, 4, -5][..]).unwrap(); + encoder + .write_tag(Tag::Unknown(65001), &[-1_i8][..]) + .unwrap(); + encoder + .write_tag(Tag::Unknown(65002), &[-1_i8, 2][..]) + .unwrap(); + encoder + .write_tag(Tag::Unknown(65003), &[-1_i8, 2, -3][..]) + .unwrap(); + encoder + .write_tag(Tag::Unknown(65004), &[-1_i8, 2, -3, 4][..]) + .unwrap(); + encoder + .write_tag(Tag::Unknown(65005), &[-1_i8, 2, -3, 4, -5][..]) + .unwrap(); encoder.write_tag(Tag::Unknown(65010), -1_i16).unwrap(); encoder.write_tag(Tag::Unknown(65011), -1_i16).unwrap(); - encoder.write_tag(Tag::Unknown(65012), &[-1_i16, 2][..]).unwrap(); - encoder.write_tag(Tag::Unknown(65013), &[-1_i16, 2, -3][..]).unwrap(); + encoder + .write_tag(Tag::Unknown(65012), &[-1_i16, 2][..]) + .unwrap(); + encoder + .write_tag(Tag::Unknown(65013), &[-1_i16, 2, -3][..]) + .unwrap(); encoder.write_tag(Tag::Unknown(65020), -1_i32).unwrap(); - encoder.write_tag(Tag::Unknown(65021), &[-1_i32][..]).unwrap(); - encoder.write_tag(Tag::Unknown(65022), &[-1_i32, 2][..]).unwrap(); + encoder + .write_tag(Tag::Unknown(65021), &[-1_i32][..]) + .unwrap(); + encoder + .write_tag(Tag::Unknown(65022), &[-1_i32, 2][..]) + .unwrap(); - encoder.write_tag(Tag::Unknown(65030), make_srational(-1)).unwrap(); - encoder.write_tag(Tag::Unknown(65031), &[make_srational(-1), make_srational(2)][..]).unwrap(); + encoder + .write_tag(Tag::Unknown(65030), make_srational(-1)) + .unwrap(); + encoder + .write_tag( + Tag::Unknown(65031), + &[make_srational(-1), make_srational(2)][..], + ) + .unwrap(); } //Rewind the cursor for reading @@ -265,7 +310,7 @@ fn test_signed() { assert_eq!(decoder.assert_tag_i32_vec(65002), [-1, 2]); assert_eq!(decoder.assert_tag_i32_vec(65003), [-1, 2, -3]); assert_eq!(decoder.assert_tag_i32_vec(65004), [-1, 2, -3, 4]); - assert_eq!(decoder.assert_tag_i32_vec(65005), [-1, 2, -3, 4, -5], ); + assert_eq!(decoder.assert_tag_i32_vec(65005), [-1, 2, -3, 4, -5],); assert_eq!(decoder.assert_tag_i32(65010), -1); assert_eq!(decoder.assert_tag_i32_vec(65011), [-1]); @@ -292,10 +337,14 @@ fn test_multipage_image() { // write first grayscale image (2x2 16-bit) let img1: Vec = [1, 2, 3, 4].to_vec(); - img_encoder.write_image::(2, 2, &img1[..]).unwrap(); + img_encoder + .write_image::(2, 2, &img1[..]) + .unwrap(); // write second grayscale image (3x3 8-bit) let img2: Vec = [9, 8, 7, 6, 5, 4, 3, 2, 1].to_vec(); - img_encoder.write_image::(3, 3, &img2[..]).unwrap(); + img_encoder + .write_image::(3, 3, &img2[..]) + .unwrap(); } // seek to the beginning of the file, so that it can be decoded