From 6e23274bea1ab7ca562e6e976b623ac1f17b21ff Mon Sep 17 00:00:00 2001 From: Andrew Champion Date: Sun, 9 Feb 2020 18:20:10 +0000 Subject: [PATCH 1/9] Decoder: max uncompressed length for LZW must respect buffer byte length Fixes #69. --- src/decoder/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 4836c32..007e403 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -584,7 +584,7 @@ impl Decoder { let (bytes, reader) = LZWReader::new( &mut self.reader, usize::try_from(length)?, - max_uncompressed_length + max_uncompressed_length * buffer.byte_len() )?; (bytes, Box::new(reader)) } From a439baa948ddee41997bf562c27421de28362360 Mon Sep 17 00:00:00 2001 From: Andrew Champion Date: Sun, 9 Feb 2020 18:22:07 +0000 Subject: [PATCH 2/9] Decoder: remove test make wrong assumption The byte count for strips is the compressed length. The compressed length may be larger than the uncompressed length, especially with poor compression choices (multi-byte samples with packbits) or small images. --- src/decoder/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 007e403..a2cd6a0 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -744,7 +744,7 @@ impl Decoder { let buffer_size = usize::try_from(self.width)? * strip_height * self.bits_per_sample.len(); - if buffer.len() < buffer_size || usize::try_from(byte_count)? / buffer.byte_len() > buffer_size { + if buffer.len() < buffer_size { return Err(TiffError::FormatError( TiffFormatError::InconsistentSizesEncountered, )); From 24d347ecf5fd862c4880f3f757b393075e9e40c1 Mon Sep 17 00:00:00 2001 From: Andrew Champion Date: Sun, 9 Feb 2020 18:23:53 +0000 Subject: [PATCH 3/9] Tests: add regression test for issue 69 --- tests/decode_images.rs | 6 ++++++ tests/images/issue_69_lzw.tiff | Bin 0 -> 2941 bytes tests/images/issue_69_packbits.tiff | Bin 0 -> 4427 bytes 3 files changed, 6 insertions(+) create mode 100644 tests/images/issue_69_lzw.tiff create mode 100644 tests/images/issue_69_packbits.tiff diff --git a/tests/decode_images.rs b/tests/decode_images.rs index 9fc8676..09685e3 100644 --- a/tests/decode_images.rs +++ b/tests/decode_images.rs @@ -149,6 +149,12 @@ fn test_decode_data() { } } +#[test] +fn issue_69() { + test_image_sum_u16("issue_69_lzw.tiff", ColorType::Gray(16), 1015486); + test_image_sum_u16("issue_69_packbits.tiff", ColorType::Gray(16), 1015486); +} + // TODO: GrayA support //#[test] //fn test_gray_alpha_u8() diff --git a/tests/images/issue_69_lzw.tiff b/tests/images/issue_69_lzw.tiff new file mode 100644 index 0000000000000000000000000000000000000000..3870fc6111ed99c1a302371ae3c21ea4906fcaf2 GIT binary patch literal 2941 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 literal 0 HcmV?d00001 diff --git a/tests/images/issue_69_packbits.tiff b/tests/images/issue_69_packbits.tiff new file mode 100644 index 0000000000000000000000000000000000000000..224edc08b63f2db7e7e908da4bfe6e6b888620b1 GIT binary patch literal 4427 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 Date: Mon, 1 Jun 2020 19:35:57 +0200 Subject: [PATCH 4/9] Update notes and metadata for 0.5.0 --- CHANGES.md | 9 +++++++++ Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 08e145b..f0d4d0a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,12 @@ +# Version 0.5.0 + +* Added support for 32-bit and 64-bit decoded values. +* Added CMYK(16|32|64) color type support. +* Check many internal integer conversions to increase stability. This should + only lead to images being reported as faulty that would previously silently + break platform limits. If there are any false positives, please report them. +* Remove an erroneous check of decoded length in lzw compressed images. + # Version 0.4.0 * Several enumerations are now non_exhaustive for future extensions. diff --git a/Cargo.toml b/Cargo.toml index c0d2dd0..ee78534 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tiff" -version = "0.4.0" +version = "0.5.0" authors = [ "ccgn", "bvssvni ", From 9f4873bae88bb1dfd9f457d0f6f5f46c4dce9610 Mon Sep 17 00:00:00 2001 From: Etienne Prothon Date: Wed, 15 Jul 2020 16:21:09 +0200 Subject: [PATCH 5/9] fix: Read ascii encoded in offset --- src/decoder/ifd.rs | 14 +++++++++++--- src/decoder/mod.rs | 10 ++++++---- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/decoder/ifd.rs b/src/decoder/ifd.rs index 58965d1..b41c981 100644 --- a/src/decoder/ifd.rs +++ b/src/decoder/ifd.rs @@ -198,9 +198,17 @@ impl Entry { if n > limits.decoding_buffer_size { return Err(TiffError::LimitsExceeded); } - decoder.goto_offset(self.r(bo).read_u32()?)?; - let string = decoder.read_string(n)?; - Ok(Ascii(string)) + if n <= 4 { + let mut buf = vec![0; n]; + self.r(bo).read_exact(&mut buf ).unwrap(); + let v = String::from_utf8(buf).unwrap(); + let v = v.trim_matches(char::from(0)); + Ok(Ascii(v.into())) + } else { + decoder.goto_offset(self.r(bo).read_u32()?)?; + let string = decoder.read_string(n)?; + Ok(Ascii(string)) + } } _ => Err(TiffError::UnsupportedError( TiffUnsupportedError::UnsupportedDataType, diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index a2cd6a0..4175352 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -424,11 +424,13 @@ impl Decoder { /// Reads a string #[inline] pub fn read_string(&mut self, length: usize) -> TiffResult { - let mut out = String::with_capacity(length); - self.reader.read_to_string(&mut out)?; + let mut out = vec![0; length]; + self.reader.read_exact(&mut out)?; // Strings may be null-terminated, so we trim anything downstream of the null byte - let trimmed = out.bytes().take_while(|&n| n != 0).collect::>(); - Ok(String::from_utf8(trimmed)?) + if let Some(first) = out.iter().position(|&b| b == 0) { + out.truncate(first); + } + Ok(String::from_utf8(out)?) } /// Reads a TIFF IFA offset/value field From 9edc0e656e0fb8b0d029527b541f89509761f45a Mon Sep 17 00:00:00 2001 From: Etienne Prothon Date: Wed, 15 Jul 2020 16:39:00 +0200 Subject: [PATCH 6/9] fix: remove unwrap --- src/decoder/ifd.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/decoder/ifd.rs b/src/decoder/ifd.rs index b41c981..444597e 100644 --- a/src/decoder/ifd.rs +++ b/src/decoder/ifd.rs @@ -200,8 +200,8 @@ impl Entry { } if n <= 4 { let mut buf = vec![0; n]; - self.r(bo).read_exact(&mut buf ).unwrap(); - let v = String::from_utf8(buf).unwrap(); + 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())) } else { From cbb41fd479a006ccabdc007504872fd84bf1f3ef Mon Sep 17 00:00:00 2001 From: Etienne Prothon Date: Wed, 15 Jul 2020 16:55:34 +0200 Subject: [PATCH 7/9] feat: Support tile and sample format tags --- src/tags.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tags.rs b/src/tags.rs index fabb74d..47caaff 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -105,6 +105,11 @@ pub enum Tag(u16) unknown("A private or extension tag") { YResolution = 283, // Advanced tags Predictor = 317, + TileWidth = 322, + TileLength = 323, + TileOffsets = 324, + TileByteCounts = 325, + SampleFormat = 339, } } From aa49e7d6f09e61e404fae25e295a9f5163719c0d Mon Sep 17 00:00:00 2001 From: Spencer Nelson Date: Tue, 21 Jul 2020 09:23:12 -0700 Subject: [PATCH 8/9] Update link to TIFF specification in docs Adobe refactored their site and the specification has moved. --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 7dec5ba..9906732 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,7 @@ //! lossless and lossy compression. //! //! # Related Links -//! * - The TIFF specification +//! * - The TIFF specification extern crate byteorder; extern crate lzw; From ba1daa18b2261a7e251c60bfaaae4df02fde465e Mon Sep 17 00:00:00 2001 From: Farkal Date: Mon, 27 Jul 2020 11:29:09 +0200 Subject: [PATCH 9/9] Allow custom encoding process (#84) Simplify encoding of tags --- src/encoder/mod.rs | 52 +++++++++++++++++++++++++++--------------- tests/encode_images.rs | 10 +++++--- 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/encoder/mod.rs b/src/encoder/mod.rs index 22e39d3..df9a2a5 100644 --- a/src/encoder/mod.rs +++ b/src/encoder/mod.rs @@ -407,26 +407,9 @@ impl TiffEncoder { where [C::Inner]: TiffValue, { - let num_pix = usize::try_from(width)?.checked_mul(usize::try_from(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()); - } - let encoder = DirectoryEncoder::new(&mut self.writer)?; - let mut image: ImageEncoder = ImageEncoder::new(encoder, width, height)?; - - let mut idx = 0; - while image.next_strip_sample_count() > 0 { - let sample_count = usize::try_from(image.next_strip_sample_count())?; - image.write_strip(&data[idx..idx + sample_count])?; - idx += sample_count; - } - image.finish() + let image: ImageEncoder = ImageEncoder::new(encoder, width, height)?; + image.write_data(data) } } @@ -548,10 +531,14 @@ impl<'a, W: Write + Seek> Drop for DirectoryEncoder<'a, W> { /// # let mut file = std::io::Cursor::new(Vec::new()); /// # let image_data = vec![0; 100*100*3]; /// use tiff::encoder::*; +/// use tiff::tags::Tag; /// /// let mut tiff = TiffEncoder::new(&mut file).unwrap(); /// let mut image = tiff.new_image::(100, 100).unwrap(); /// +/// // You can encode tags here +/// image.encoder().write_tag(Tag::Artist, "Image-tiff").unwrap(); +/// /// let mut idx = 0; /// while image.next_strip_sample_count() > 0 { /// let sample_count = image.next_strip_sample_count() as usize; @@ -561,11 +548,13 @@ impl<'a, W: Write + Seek> Drop for DirectoryEncoder<'a, W> { /// image.finish().unwrap(); /// # } /// ``` +/// You can also call write_data function wich will encode by strip and finish pub struct ImageEncoder<'a, W: 'a + Write + Seek, C: ColorType> { encoder: DirectoryEncoder<'a, W>, strip_idx: u64, strip_count: u64, row_samples: u64, + width: u32, height: u32, rows_per_strip: u64, strip_offsets: Vec, @@ -608,6 +597,7 @@ impl<'a, W: 'a + Write + Seek, T: ColorType> ImageEncoder<'a, W, T> { strip_idx: 0, row_samples, rows_per_strip, + width, height, strip_offsets: Vec::new(), strip_byte_count: Vec::new(), @@ -652,6 +642,30 @@ impl<'a, W: 'a + Write + Seek, T: ColorType> ImageEncoder<'a, W, T> { Ok(()) } + /// Write strips from data + pub fn write_data(mut self, data: &[T::Inner]) -> TiffResult<()> + 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"))?; + if data.len() < num_pix { + return Err(::std::io::Error::new( + ::std::io::ErrorKind::InvalidData, + "Input data slice is undersized for provided dimensions").into()); + } + let mut idx = 0; + while self.next_strip_sample_count() > 0 { + let sample_count = usize::try_from(self.next_strip_sample_count())?; + self.write_strip(&data[idx..idx + sample_count])?; + idx += sample_count; + } + self.finish()?; + Ok(()) + } + /// Set image resolution pub fn resolution(&mut self, unit: ResolutionUnit, value: Rational) { self.encoder.write_tag(Tag::ResolutionUnit, unit.to_u16()).unwrap(); diff --git a/tests/encode_images.rs b/tests/encode_images.rs index 9d1ecfd..9ba1cd3 100644 --- a/tests/encode_images.rs +++ b/tests/encode_images.rs @@ -1,6 +1,6 @@ extern crate tiff; -use tiff::decoder::{Decoder, DecodingResult}; +use tiff::decoder::{Decoder, DecodingResult, ifd}; use tiff::encoder::{colortype, TiffEncoder, SRational}; use tiff::ColorType; use tiff::tags::Tag; @@ -24,14 +24,18 @@ fn encode_decode() { { let mut tiff = TiffEncoder::new(&mut file).unwrap(); - tiff.write_image::(100, 100, &image_data) + let mut image = tiff.new_image::(100, 100) .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())); if let DecodingResult::U8(img_res) = decoder.read_image().unwrap() { assert_eq!(image_data, img_res); } else { @@ -259,4 +263,4 @@ fn test_multipage_image() { // check the dimensions of the image in the second page assert_eq!(img_decoder.dimensions().unwrap(), (3, 3)); } -} +} \ No newline at end of file