From 80b8ec5cdbe4ea98817a92ee8206d0bc80750c88 Mon Sep 17 00:00:00 2001 From: Onno Kammeraad Date: Wed, 6 Nov 2019 13:58:29 +0100 Subject: [PATCH 1/6] Somehow the current offset was invalid when using multipage images. Now using the seek function to get the current offset --- src/encoder/writer.rs | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/src/encoder/writer.rs b/src/encoder/writer.rs index 78a128d..218503a 100644 --- a/src/encoder/writer.rs +++ b/src/encoder/writer.rs @@ -10,7 +10,6 @@ impl TiffByteOrder for LittleEndian { fn write_header(writer: &mut TiffWriter) -> TiffResult<()> { writer.writer.write_u16::(0x4949)?; writer.writer.write_u16::(42)?; - writer.offset += 4; Ok(()) } @@ -20,7 +19,6 @@ impl TiffByteOrder for BigEndian { fn write_header(writer: &mut TiffWriter) -> TiffResult<()> { writer.writer.write_u16::(0x4d4d)?; writer.writer.write_u16::(42)?; - writer.offset += 4; Ok(()) } @@ -28,75 +26,66 @@ impl TiffByteOrder for BigEndian { pub struct TiffWriter { writer: W, - offset: u64, } impl TiffWriter { pub fn new(writer: W) -> Self { - Self { writer, offset: 0 } - } - - pub fn offset(&self) -> u64 { - self.offset + Self { writer } } pub fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), io::Error> { self.writer.write_all(bytes)?; - self.offset += bytes.len() as u64; Ok(()) } pub fn write_u8(&mut self, n: u8) -> Result<(), io::Error> { self.writer.write_u8(n)?; - self.offset += 1; Ok(()) } pub fn write_i8(&mut self, n: i8) -> Result<(), io::Error> { self.writer.write_i8(n)?; - self.offset += 1; Ok(()) } pub fn write_u16(&mut self, n: u16) -> Result<(), io::Error> { self.writer.write_u16::(n)?; - self.offset += 2; Ok(()) } pub fn write_i16(&mut self, n: i16) -> Result<(), io::Error> { self.writer.write_i16::(n)?; - self.offset += 2; Ok(()) } pub fn write_u32(&mut self, n: u32) -> Result<(), io::Error> { self.writer.write_u32::(n)?; - self.offset += 4; Ok(()) } pub fn write_i32(&mut self, n: i32) -> Result<(), io::Error> { self.writer.write_i32::(n)?; - self.offset += 4; Ok(()) } pub fn write_u64(&mut self, n: u64) -> Result<(), io::Error> { self.writer.write_u64::(n)?; - self.offset += 8; Ok(()) } +} + +impl TiffWriter { pub fn pad_word_boundary(&mut self) -> Result<(), io::Error> { - if self.offset % 4 != 0 { + let offset = self.offset(); + if offset % 4 != 0 { let padding = [0, 0, 0]; - let padd_len = 4 - (self.offset % 4); + let padd_len = 4 - (offset % 4); self.writer.write_all(&padding[..padd_len as usize])?; } @@ -106,8 +95,11 @@ impl TiffWriter { impl TiffWriter { pub fn goto_offset(&mut self, offset: u64) -> Result<(), io::Error> { - self.offset = offset; self.writer.seek(SeekFrom::Start(offset as u64))?; Ok(()) } + + pub fn offset(&mut self) -> u64 { + self.writer.seek(SeekFrom::Current(0)).unwrap() + } } From cbae42ea94163707d799a1569f2aca1842d00480 Mon Sep 17 00:00:00 2001 From: Onno Kammeraad Date: Wed, 6 Nov 2019 14:04:18 +0100 Subject: [PATCH 2/6] fixed support for multipage images, the IDF offset is added during the new and also at the end of the internal_finish. This should only be done once --- src/encoder/mod.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/encoder/mod.rs b/src/encoder/mod.rs index 96ba414..ab626cf 100644 --- a/src/encoder/mod.rs +++ b/src/encoder/mod.rs @@ -1,6 +1,7 @@ use byteorder::NativeEndian; use std::collections::BTreeMap; use std::io::{Seek, Write}; +use std::mem; use decoder::ifd::{self, Tag}; use error::{TiffError, TiffFormatError, TiffResult}; @@ -351,6 +352,8 @@ impl TiffEncoder { }; NativeEndian::write_header(&mut encoder.writer)?; + // blank the IFD offset location + encoder.writer.write_u32(0)?; Ok(encoder) } @@ -417,9 +420,9 @@ pub struct DirectoryEncoder<'a, W: 'a + Write + Seek> { impl<'a, W: 'a + Write + Seek> DirectoryEncoder<'a, W> { fn new(writer: &'a mut TiffWriter) -> TiffResult> { + // the previous word is the IFD offset position + let ifd_pointer_pos = writer.offset() - mem::size_of::() as u64; writer.pad_word_boundary()?; - let ifd_pointer_pos = writer.offset(); - writer.write_u32(0)?; Ok(DirectoryEncoder { writer, dropped: false, From 686e9b264869ceefeb36409b014ae2b05e7a416f Mon Sep 17 00:00:00 2001 From: Onno Kammeraad Date: Mon, 11 Nov 2019 16:15:01 +0100 Subject: [PATCH 3/6] added a missing offset increase while adding padding --- src/encoder/writer.rs | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/encoder/writer.rs b/src/encoder/writer.rs index 218503a..ba4c4c5 100644 --- a/src/encoder/writer.rs +++ b/src/encoder/writer.rs @@ -10,6 +10,7 @@ impl TiffByteOrder for LittleEndian { fn write_header(writer: &mut TiffWriter) -> TiffResult<()> { writer.writer.write_u16::(0x4949)?; writer.writer.write_u16::(42)?; + writer.offset += 4; Ok(()) } @@ -19,6 +20,7 @@ impl TiffByteOrder for BigEndian { fn write_header(writer: &mut TiffWriter) -> TiffResult<()> { writer.writer.write_u16::(0x4d4d)?; writer.writer.write_u16::(42)?; + writer.offset += 4; Ok(()) } @@ -26,67 +28,77 @@ impl TiffByteOrder for BigEndian { pub struct TiffWriter { writer: W, + offset: u64, } impl TiffWriter { pub fn new(writer: W) -> Self { - Self { writer } + Self { writer, offset: 0 } + } + + pub fn offset(&self) -> u64 { + self.offset } pub fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), io::Error> { self.writer.write_all(bytes)?; + self.offset += bytes.len() as u64; Ok(()) } pub fn write_u8(&mut self, n: u8) -> Result<(), io::Error> { self.writer.write_u8(n)?; + self.offset += 1; Ok(()) } pub fn write_i8(&mut self, n: i8) -> Result<(), io::Error> { self.writer.write_i8(n)?; + self.offset += 1; Ok(()) } pub fn write_u16(&mut self, n: u16) -> Result<(), io::Error> { self.writer.write_u16::(n)?; + self.offset += 2; Ok(()) } pub fn write_i16(&mut self, n: i16) -> Result<(), io::Error> { self.writer.write_i16::(n)?; + self.offset += 2; Ok(()) } pub fn write_u32(&mut self, n: u32) -> Result<(), io::Error> { self.writer.write_u32::(n)?; + self.offset += 4; Ok(()) } pub fn write_i32(&mut self, n: i32) -> Result<(), io::Error> { self.writer.write_i32::(n)?; + self.offset += 4; Ok(()) } pub fn write_u64(&mut self, n: u64) -> Result<(), io::Error> { self.writer.write_u64::(n)?; + self.offset += 8; Ok(()) } -} - -impl TiffWriter { pub fn pad_word_boundary(&mut self) -> Result<(), io::Error> { - let offset = self.offset(); - if offset % 4 != 0 { + if self.offset % 4 != 0 { let padding = [0, 0, 0]; - let padd_len = 4 - (offset % 4); + let padd_len = 4 - (self.offset % 4); self.writer.write_all(&padding[..padd_len as usize])?; + self.offset += padd_len; } Ok(()) @@ -95,11 +107,8 @@ impl TiffWriter { impl TiffWriter { pub fn goto_offset(&mut self, offset: u64) -> Result<(), io::Error> { + self.offset = offset; self.writer.seek(SeekFrom::Start(offset as u64))?; Ok(()) } - - pub fn offset(&mut self) -> u64 { - self.writer.seek(SeekFrom::Current(0)).unwrap() - } } From b2eb480c440f96f222145056b3edcfb1be8ac80c Mon Sep 17 00:00:00 2001 From: Onno Kammeraad Date: Tue, 12 Nov 2019 09:44:27 +0100 Subject: [PATCH 4/6] add multipage testcase, to validate the multipage image handling --- tests/encode_images.rs | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/tests/encode_images.rs b/tests/encode_images.rs index 2ae8c1c..1c7d313 100644 --- a/tests/encode_images.rs +++ b/tests/encode_images.rs @@ -260,4 +260,35 @@ fn test_signed() { assert_eq!(decoder.get_tag(Tag::Unknown(65030)).unwrap().into_i32_vec().unwrap(), [-1, 100]); assert_eq!(decoder.get_tag(Tag::Unknown(65031)).unwrap().into_i32_vec().unwrap(), [-1_i32, 100, 2, 100]); } -} \ No newline at end of file +} + +#[test] +/// check multipage image handling +fn test_multipage_image() { + let mut img_file = tempfile::tempfile().unwrap(); + + { + // first create a multipage image with 2 images + let mut img_encoder = TiffEncoder::new(&img_file).unwrap(); + + // write first grayscale image (2x2 16-bit) + let img1: Vec = [1, 2, 3, 4].to_vec(); + img_encoder.write_image::(2, 2, &img1[..]); + // 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[..]); + } + + // seek to the beginning of the file, so that it can be decoded + img_file.seek(SeekFrom::Start(0)).unwrap(); + + { + let mut img_decoder = Decoder::new(&img_file).unwrap(); + + // check the dimensions of the image in the first page + assert_eq!(img_decoder.dimensions().unwrap(), (2, 2)); + img_decoder.next_image().unwrap(); + // check the dimensions of the image in the second page + assert_eq!(img_decoder.dimensions().unwrap(), (3, 3)); + } +} From f70447325e74fa92070923bf754dfe7d57cdf6f5 Mon Sep 17 00:00:00 2001 From: Onno <57527367+onnotechno@users.noreply.github.com> Date: Tue, 12 Nov 2019 10:40:19 +0100 Subject: [PATCH 5/6] Update tests/encode_images.rs Co-Authored-By: HeroicKatora --- tests/encode_images.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/encode_images.rs b/tests/encode_images.rs index 1c7d313..2d44853 100644 --- a/tests/encode_images.rs +++ b/tests/encode_images.rs @@ -265,7 +265,7 @@ fn test_signed() { #[test] /// check multipage image handling fn test_multipage_image() { - let mut img_file = tempfile::tempfile().unwrap(); + let mut img_file = Cursor::new(Vec::new()); { // first create a multipage image with 2 images From fd789dc420922edb65dd738d1f691574b0f008f9 Mon Sep 17 00:00:00 2001 From: Onno Kammeraad Date: Tue, 12 Nov 2019 13:09:09 +0100 Subject: [PATCH 6/6] Cursor::new(Vec::new()) requires a &mut instead of just & --- tests/encode_images.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/encode_images.rs b/tests/encode_images.rs index 2d44853..6256cec 100644 --- a/tests/encode_images.rs +++ b/tests/encode_images.rs @@ -269,7 +269,7 @@ fn test_multipage_image() { { // first create a multipage image with 2 images - let mut img_encoder = TiffEncoder::new(&img_file).unwrap(); + let mut img_encoder = TiffEncoder::new(&mut img_file).unwrap(); // write first grayscale image (2x2 16-bit) let img1: Vec = [1, 2, 3, 4].to_vec(); @@ -283,7 +283,7 @@ fn test_multipage_image() { img_file.seek(SeekFrom::Start(0)).unwrap(); { - let mut img_decoder = Decoder::new(&img_file).unwrap(); + let mut img_decoder = Decoder::new(&mut img_file).unwrap(); // check the dimensions of the image in the first page assert_eq!(img_decoder.dimensions().unwrap(), (2, 2));