From 9f4873bae88bb1dfd9f457d0f6f5f46c4dce9610 Mon Sep 17 00:00:00 2001 From: Etienne Prothon Date: Wed, 15 Jul 2020 16:21:09 +0200 Subject: [PATCH 1/5] 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 2/5] 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 3/5] 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 4/5] 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 5/5] 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