From 647de77b707af0897cf8070844a9cf98a78b8621 Mon Sep 17 00:00:00 2001 From: raph Date: Thu, 10 Sep 2020 18:37:15 +0200 Subject: [PATCH 01/18] Add support for UNDEFINED type According to TIFF spec this is an byte-array that may contain arbitrary data. --- src/decoder/ifd.rs | 5 ++++- src/tags.rs | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/decoder/ifd.rs b/src/decoder/ifd.rs index d11319b..e8f8f16 100644 --- a/src/decoder/ifd.rs +++ b/src/decoder/ifd.rs @@ -425,7 +425,10 @@ impl Entry { let string = decoder.read_string(n)?; Ok(Ascii(string)) } - } + }, + (Type::UNDEFINED, n) => self.decode_offset(n, bo, limits, decoder, |decoder| { + Ok(Unsigned(u32::from(decoder.read_byte()?))) + }), _ => Err(TiffError::UnsupportedError( TiffUnsupportedError::UnsupportedDataType, )), diff --git a/src/tags.rs b/src/tags.rs index d28808a..1364fa6 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -130,6 +130,7 @@ pub enum Type(u16) { LONG = 4, RATIONAL = 5, SBYTE = 6, + UNDEFINED = 7, SSHORT = 8, SLONG = 9, SRATIONAL = 10, From da9bdac8a260fd0da90fcbdb4e5d776ee3e2cab3 Mon Sep 17 00:00:00 2001 From: ruffson Date: Fri, 25 Sep 2020 15:47:29 +0200 Subject: [PATCH 02/18] Read out byte-sized arrays --- src/decoder/ifd.rs | 30 +++++++++++++++++++++++++++++- src/decoder/mod.rs | 5 +++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/decoder/ifd.rs b/src/decoder/ifd.rs index e8f8f16..acbe484 100644 --- a/src/decoder/ifd.rs +++ b/src/decoder/ifd.rs @@ -10,13 +10,14 @@ use tags::{Tag, Type}; use {TiffError, TiffFormatError, TiffResult, TiffUnsupportedError}; use self::Value::{ - Ascii, Double, Float, List, Rational, RationalBig, SRational, SRationalBig, Signed, SignedBig, + Ascii, Byte, Double, Float, List, Rational, RationalBig, SRational, SRationalBig, Signed, SignedBig, Unsigned, UnsignedBig, }; #[allow(unused_qualifications)] #[derive(Debug, Clone, PartialEq)] pub enum Value { + Byte(u8), Signed(i32), SignedBig(i64), Unsigned(u32), @@ -34,6 +35,16 @@ pub enum Value { } impl Value { + + pub fn into_u8(self) -> TiffResult { + match self { + Byte(val) => Ok(val), + val => Err(TiffError::FormatError( + TiffFormatError::UnsignedIntegerExpected(val), + )), + } + } + pub fn into_u32(self) -> TiffResult { match self { Unsigned(val) => Ok(val), @@ -114,6 +125,23 @@ impl Value { } } + pub fn into_u8_vec(self) -> TiffResult> { + match self { + List(vec) => { + let mut new_vec = Vec::with_capacity(vec.len()); + for v in vec { + new_vec.push(v.into_u8()?) + } + Ok(new_vec) + } + Byte(val) => Ok(vec![val]), + + val => Err(TiffError::FormatError( + TiffFormatError::UnsignedIntegerExpected(val), + )), + } + } + pub fn into_i32_vec(self) -> TiffResult> { match self { List(vec) => { diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 6d6281f..40dd25c 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -746,6 +746,11 @@ impl Decoder { self.get_tag(tag)?.into_f64_vec() } + /// Tries to retrieve a tag and convert it to a 8bit vector. + pub fn get_tag_u8_vec(&mut self, tag: Tag) -> TiffResult> { + self.get_tag(tag)?.into_u8_vec() + } + /// Decompresses the strip into the supplied buffer. /// Returns the number of bytes read. fn expand_strip<'a>( From 2cb57a4d04a4b142055086bf3613113f1fa7ec22 Mon Sep 17 00:00:00 2001 From: ruffson Date: Fri, 25 Sep 2020 16:10:16 +0200 Subject: [PATCH 03/18] Add initial support for modern JPEG compression Some things still need to be done: - Check RGB images - Check small images - Check huffman-only jpeg tables - Check empty jpeg tables - Add tests --- Cargo.toml | 1 + src/decoder/mod.rs | 86 ++++++++++++++++++++++++++++++++++++++++++- src/decoder/stream.rs | 86 +++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/tags.rs | 11 ++++++ 5 files changed, 184 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index eb644d5..268e58a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ exclude = ["tests/images/*", "tests/fuzz_images/*"] [dependencies] weezl = "0.1.0" +jpeg = { package = "jpeg-decoder", version = "0.1.17", default-features = false } [dependencies.miniz_oxide] version = "0.4.1" diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 40dd25c..17420ee 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -9,7 +9,7 @@ use self::ifd::Directory; use tags::{CompressionMethod, PhotometricInterpretation, Predictor, SampleFormat, Tag, Type}; use self::stream::{ - ByteOrder, DeflateReader, EndianReader, LZWReader, PackBitsReader, SmartReader, +ByteOrder, DeflateReader, EndianReader, LZWReader, PackBitsReader, SmartReader, JpegReader }; pub mod ifd; @@ -710,6 +710,32 @@ impl Decoder { } } + pub fn get_all_tags(&mut self) -> Vec<(Tag, ifd::Value)> { + let mut all_tags = Vec::new(); + + let dir = match &self.ifd { + Some(d) => d, + None => { + println!("No tags found"); + return all_tags; + } + }; + let keys = dir.keys().cloned().collect::>(); + // go through all tags + for key in keys { + let tag_value = match self.get_tag(key) { + Ok(val) => val, + _ => { + println!("Could not unwrap {:?}", key); + continue; + } + }; + all_tags.push((key, tag_value)); + } + + all_tags + } + /// Tries to retrieve a tag and convert it to the desired type. pub fn get_tag_u32(&mut self, tag: Tag) -> TiffResult { self.get_tag(tag)?.into_u32() @@ -928,6 +954,56 @@ impl Decoder { Ok(()) } + pub fn read_jpeg_tiles(&mut self) -> TiffResult { + let tile_offsets = self.get_tag_u32_vec(Tag::TileOffsets)?; + let tile_bytes = self.get_tag_u32_vec(Tag::TileByteCounts)?; + let jpeg_tables: Vec = self.get_tag_u8_vec(Tag::JPEGTables)?; + + let mut res_img = Vec::with_capacity(tile_offsets[0] as usize); + + for (idx, offset) in tile_offsets.iter().enumerate() { + + self.goto_offset(*offset)?; + let jpeg_reader = JpegReader::new(&mut self.reader, tile_bytes[idx], &jpeg_tables)?; + let mut decoder = jpeg::Decoder::new(jpeg_reader); + + match decoder.decode() { + Err(e) => { + panic!("The ERror was: {}", e); + }, + Ok(mut val) => res_img.append(&mut val), + } + } + + Ok(DecodingResult::U8(res_img)) + + } + + pub fn read_jpeg_strips(&mut self) -> TiffResult { + let strip_offsets = self.get_tag_u32_vec(Tag::StripOffsets)?; + let strip_bytes = self.get_tag_u32_vec(Tag::StripByteCounts)?; + let jpeg_tables: Vec = self.get_tag_u8_vec(Tag::JPEGTables)?; + + let mut res_img = Vec::with_capacity(strip_offsets[0] as usize); + + for (idx, offset) in strip_offsets.iter().enumerate() { + + self.goto_offset(*offset)?; + let jpeg_reader = JpegReader::new(&mut self.reader, strip_bytes[idx], &jpeg_tables)?; + let mut decoder = jpeg::Decoder::new(jpeg_reader); + + match decoder.decode() { + Err(e) => { + panic!("Error when reading jpeg tiles: {}", e); + }, + Ok(mut val) => res_img.append(&mut val), + } + } + + Ok(DecodingResult::U8(res_img)) + } + + pub fn read_strip_to_buffer(&mut self, mut buffer: DecodingBuffer) -> TiffResult<()> { self.initialize_strip_decoder()?; @@ -1050,6 +1126,14 @@ impl Decoder { /// Decodes the entire image and return it as a Vector pub fn read_image(&mut self) -> TiffResult { + + if self.compression_method == CompressionMethod::ModernJPEG { + match self.find_tag(Tag::TileOffsets) { + Ok(None) | Err(_) => return self.read_jpeg_strips(), + Ok(_) => return self.read_jpeg_tiles(), + } + } + self.initialize_strip_decoder()?; let rows_per_strip = usize::try_from(self.get_tag_u32(Tag::RowsPerStrip).unwrap_or(self.height))?; diff --git a/src/decoder/stream.rs b/src/decoder/stream.rs index 7c7affd..56ef877 100644 --- a/src/decoder/stream.rs +++ b/src/decoder/stream.rs @@ -187,6 +187,14 @@ pub trait EndianReader: Read { } } +/// +/// # READERS +/// + +/// +/// ## Deflate Reader +/// + /// Reader that decompresses DEFLATE streams pub struct DeflateReader { buffer: io::Cursor>, @@ -233,6 +241,10 @@ impl EndianReader for DeflateReader { } } +/// +/// ## LZW Reader +/// + /// Reader that decompresses LZW streams pub struct LZWReader { buffer: io::Cursor>, @@ -306,6 +318,76 @@ impl EndianReader for LZWReader { } } +/// +/// ## JPEG Reader (for "new-style" JPEG format (TIFF compression tag 7)) +/// + +pub struct JpegReader { + buffer: io::Cursor>, + byte_order: ByteOrder, // for jpeg image data always ..., +} +// Only tested with qtables in jpegtables, but it contain both qtables and huffman tables or either +impl JpegReader { + /// Constructs new JpegReader wrapping a SmartReader. + /// Because Jpeg compression in TIFF allows to save quantization and/or huffman tables in one + /// central loacation, the constructor accepts this data as `jpeg_tables` here containing either + /// both. + /// These `jpeg_tables` are simply prepended to the remaining jpeg image data. + /// Because these jpegtables start with a `SOI` (HEX: `0xFFD8`) or __start of image__ marker + /// which is also at the beginning of the remaining jpeg image data and would + /// confuse the jpeg renderer, one of these has to be taken off. In this case the first two + /// bytes of the remaining jpeg data is removed because this follows `jpeg_tables`. + /// Similary, `jpeg_tables` ends with a `EOI` (HEX: `0xFFD9`) or __end of image__ marker, + /// this has to be removed as well (last two bytes of `jpeg_tables`). + + pub fn new( + reader: &mut SmartReader, + length: u32, + jpeg_tables: &Vec + ) -> io::Result + where + R: Read + Seek, + { + let order = reader.byte_order; + + // Read jpeg image data + let mut segment = vec![0; length as usize]; + reader.read_exact(&mut segment[..])?; + + let mut jpeg_data = jpeg_tables.clone(); + jpeg_data.truncate(jpeg_data.len() - 2); + + jpeg_data.extend_from_slice(&mut segment[2..]); + + Ok( + JpegReader { + buffer: io::Cursor::new(jpeg_data), + byte_order: order, + }, + ) + } +} + +impl Read for JpegReader { + // #[inline] + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.buffer.read(buf) + } +} + +impl EndianReader for JpegReader { + #[inline(always)] + fn byte_order(&self) -> ByteOrder { + self.byte_order + } +} + + + +/// +/// ## PackBits Reader +/// + /// Reader that unpacks Apple's `PackBits` format pub struct PackBitsReader { buffer: io::Cursor>, @@ -378,6 +460,10 @@ impl EndianReader for PackBitsReader { } } +/// +/// ## SmartReader Reader +/// + /// Reader that is aware of the byte order. #[derive(Debug)] pub struct SmartReader diff --git a/src/lib.rs b/src/lib.rs index f9346cb..4867d61 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,7 @@ extern crate miniz_oxide; extern crate weezl; +extern crate jpeg; mod bytecast; pub mod decoder; diff --git a/src/tags.rs b/src/tags.rs index 1364fa6..a4e03f6 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -111,6 +111,13 @@ pub enum Tag(u16) unknown("A private or extension tag") { Threshholding = 263, // TODO add support XResolution = 282, YResolution = 283, + // JPEG + TileWidth = 322, + TileLength = 323, + TileOffsets = 324, + TileByteCounts = 325, + SampleFormat = 339, + JPEGTables = 347, // Advanced tags Predictor = 317, TileWidth = 322, @@ -142,6 +149,8 @@ pub enum Type(u16) { } tags! { +/// See [TIFF compression tags](https://www.awaresystems.be/imaging/tiff/tifftags/compression.html) +/// for reference. pub enum CompressionMethod(u16) { None = 1, Huffman = 2, @@ -149,6 +158,8 @@ pub enum CompressionMethod(u16) { Fax4 = 4, LZW = 5, JPEG = 6, + // "Extended JPEG" or "new JPEG" style + ModernJPEG = 7, Deflate = 8, OldDeflate = 0x80B2, PackBits = 0x8005, From a510b03e1cfd500097745d07ce681657711248da Mon Sep 17 00:00:00 2001 From: ruffson Date: Fri, 25 Sep 2020 16:21:09 +0200 Subject: [PATCH 04/18] Apply auto-format to modified files --- src/decoder/ifd.rs | 1 - src/decoder/mod.rs | 18 ++++++++---------- src/decoder/stream.rs | 14 +++++--------- tests/decode_images.rs | 2 +- 4 files changed, 14 insertions(+), 21 deletions(-) diff --git a/src/decoder/ifd.rs b/src/decoder/ifd.rs index acbe484..f1daae7 100644 --- a/src/decoder/ifd.rs +++ b/src/decoder/ifd.rs @@ -35,7 +35,6 @@ pub enum Value { } impl Value { - pub fn into_u8(self) -> TiffResult { match self { Byte(val) => Ok(val), diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 17420ee..b0731a9 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -9,8 +9,9 @@ use self::ifd::Directory; use tags::{CompressionMethod, PhotometricInterpretation, Predictor, SampleFormat, Tag, Type}; use self::stream::{ -ByteOrder, DeflateReader, EndianReader, LZWReader, PackBitsReader, SmartReader, JpegReader + ByteOrder, DeflateReader, EndianReader, LZWReader, PackBitsReader, SmartReader, JpegReader }; +use tags::{CompressionMethod, PhotometricInterpretation, Predictor, Tag, Type}; pub mod ifd; mod stream; @@ -638,7 +639,9 @@ impl Decoder { for _ in 0..num_tags { let (tag, entry) = match self.read_entry()? { Some(val) => val, - None => continue, // Unknown data type in tag, skip + None => { + continue; + } // Unknown data type in tag, skip }; dir.insert(tag, entry); } @@ -962,7 +965,6 @@ impl Decoder { let mut res_img = Vec::with_capacity(tile_offsets[0] as usize); for (idx, offset) in tile_offsets.iter().enumerate() { - self.goto_offset(*offset)?; let jpeg_reader = JpegReader::new(&mut self.reader, tile_bytes[idx], &jpeg_tables)?; let mut decoder = jpeg::Decoder::new(jpeg_reader); @@ -970,13 +972,12 @@ impl Decoder { match decoder.decode() { Err(e) => { panic!("The ERror was: {}", e); - }, + } Ok(mut val) => res_img.append(&mut val), } } Ok(DecodingResult::U8(res_img)) - } pub fn read_jpeg_strips(&mut self) -> TiffResult { @@ -986,8 +987,8 @@ impl Decoder { let mut res_img = Vec::with_capacity(strip_offsets[0] as usize); - for (idx, offset) in strip_offsets.iter().enumerate() { + for (idx, offset) in strip_offsets.iter().enumerate() { self.goto_offset(*offset)?; let jpeg_reader = JpegReader::new(&mut self.reader, strip_bytes[idx], &jpeg_tables)?; let mut decoder = jpeg::Decoder::new(jpeg_reader); @@ -995,7 +996,7 @@ impl Decoder { match decoder.decode() { Err(e) => { panic!("Error when reading jpeg tiles: {}", e); - }, + } Ok(mut val) => res_img.append(&mut val), } } @@ -1003,7 +1004,6 @@ impl Decoder { Ok(DecodingResult::U8(res_img)) } - pub fn read_strip_to_buffer(&mut self, mut buffer: DecodingBuffer) -> TiffResult<()> { self.initialize_strip_decoder()?; @@ -1126,7 +1126,6 @@ impl Decoder { /// Decodes the entire image and return it as a Vector pub fn read_image(&mut self) -> TiffResult { - if self.compression_method == CompressionMethod::ModernJPEG { match self.find_tag(Tag::TileOffsets) { Ok(None) | Err(_) => return self.read_jpeg_strips(), @@ -1146,7 +1145,6 @@ impl Decoder { for i in 0..usize::try_from(self.strip_count()?)? { self.read_strip_to_buffer(result.as_buffer(samples_per_strip * i))?; } - Ok(result) } } diff --git a/src/decoder/stream.rs b/src/decoder/stream.rs index 56ef877..7df3bf8 100644 --- a/src/decoder/stream.rs +++ b/src/decoder/stream.rs @@ -343,7 +343,7 @@ impl JpegReader { pub fn new( reader: &mut SmartReader, length: u32, - jpeg_tables: &Vec + jpeg_tables: &Vec, ) -> io::Result where R: Read + Seek, @@ -359,12 +359,10 @@ impl JpegReader { jpeg_data.extend_from_slice(&mut segment[2..]); - Ok( - JpegReader { - buffer: io::Cursor::new(jpeg_data), - byte_order: order, - }, - ) + Ok(JpegReader { + buffer: io::Cursor::new(jpeg_data), + byte_order: order, + }) } } @@ -382,8 +380,6 @@ impl EndianReader for JpegReader { } } - - /// /// ## PackBits Reader /// diff --git a/tests/decode_images.rs b/tests/decode_images.rs index 2336178..a92a668 100644 --- a/tests/decode_images.rs +++ b/tests/decode_images.rs @@ -170,7 +170,7 @@ fn test_decode_data() { let mut decoder = Decoder::new(file).unwrap(); assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(8)); assert_eq!(decoder.dimensions().unwrap(), (100, 100)); - if let DecodingResult::U8(img_res) = decoder.read_image().unwrap() { + if let DecodingResult::U8(img_res) = decoder.read_strip().unwrap() { assert_eq!(image_data, img_res); } else { panic!("Wrong data type"); From 46918b395ca83004474261ddfb1032736a21a044 Mon Sep 17 00:00:00 2001 From: ruffson Date: Fri, 25 Sep 2020 18:36:49 +0200 Subject: [PATCH 05/18] Condense tile and strip reading code --- src/decoder/mod.rs | 46 ++++++++++++++++------------------------------ 1 file changed, 16 insertions(+), 30 deletions(-) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index b0731a9..c9ac8f5 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -957,40 +957,25 @@ impl Decoder { Ok(()) } - pub fn read_jpeg_tiles(&mut self) -> TiffResult { - let tile_offsets = self.get_tag_u32_vec(Tag::TileOffsets)?; - let tile_bytes = self.get_tag_u32_vec(Tag::TileByteCounts)?; + pub fn read_jpeg(&mut self, read_strip_wise: bool) -> TiffResult { + + let offsets: Vec; + let bytes: Vec; let jpeg_tables: Vec = self.get_tag_u8_vec(Tag::JPEGTables)?; - let mut res_img = Vec::with_capacity(tile_offsets[0] as usize); - - for (idx, offset) in tile_offsets.iter().enumerate() { - self.goto_offset(*offset)?; - let jpeg_reader = JpegReader::new(&mut self.reader, tile_bytes[idx], &jpeg_tables)?; - let mut decoder = jpeg::Decoder::new(jpeg_reader); - - match decoder.decode() { - Err(e) => { - panic!("The ERror was: {}", e); - } - Ok(mut val) => res_img.append(&mut val), - } + if read_strip_wise { + offsets = self.get_tag_u32_vec(Tag::StripOffsets)?; + bytes = self.get_tag_u32_vec(Tag::StripByteCounts)?; + } else { + offsets = self.get_tag_u32_vec(Tag::TileOffsets)?; + bytes = self.get_tag_u32_vec(Tag::TileByteCounts)?; } - Ok(DecodingResult::U8(res_img)) - } + let mut res_img = Vec::with_capacity(offsets[0] as usize); - pub fn read_jpeg_strips(&mut self) -> TiffResult { - let strip_offsets = self.get_tag_u32_vec(Tag::StripOffsets)?; - let strip_bytes = self.get_tag_u32_vec(Tag::StripByteCounts)?; - let jpeg_tables: Vec = self.get_tag_u8_vec(Tag::JPEGTables)?; - - let mut res_img = Vec::with_capacity(strip_offsets[0] as usize); - - - for (idx, offset) in strip_offsets.iter().enumerate() { + for (idx, offset) in offsets.iter().enumerate() { self.goto_offset(*offset)?; - let jpeg_reader = JpegReader::new(&mut self.reader, strip_bytes[idx], &jpeg_tables)?; + let jpeg_reader = JpegReader::new(&mut self.reader, bytes[idx], &jpeg_tables)?; let mut decoder = jpeg::Decoder::new(jpeg_reader); match decoder.decode() { @@ -1126,10 +1111,11 @@ impl Decoder { /// Decodes the entire image and return it as a Vector pub fn read_image(&mut self) -> TiffResult { + if self.compression_method == CompressionMethod::ModernJPEG { match self.find_tag(Tag::TileOffsets) { - Ok(None) | Err(_) => return self.read_jpeg_strips(), - Ok(_) => return self.read_jpeg_tiles(), + Ok(None) | Err(_) => return self.read_jpeg(true), + Ok(_) => return self.read_jpeg(false), } } From b455bd9f2bb78068282f5d2a234c6637c898096c Mon Sep 17 00:00:00 2001 From: ruffson Date: Fri, 25 Sep 2020 18:43:04 +0200 Subject: [PATCH 06/18] Fix test --- tests/decode_images.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/decode_images.rs b/tests/decode_images.rs index a92a668..2336178 100644 --- a/tests/decode_images.rs +++ b/tests/decode_images.rs @@ -170,7 +170,7 @@ fn test_decode_data() { let mut decoder = Decoder::new(file).unwrap(); assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(8)); assert_eq!(decoder.dimensions().unwrap(), (100, 100)); - if let DecodingResult::U8(img_res) = decoder.read_strip().unwrap() { + if let DecodingResult::U8(img_res) = decoder.read_image().unwrap() { assert_eq!(image_data, img_res); } else { panic!("Wrong data type"); From 63f09b267a4c6ee80218262447d213533f3060db Mon Sep 17 00:00:00 2001 From: ruffson Date: Fri, 25 Sep 2020 18:44:28 +0200 Subject: [PATCH 07/18] Reorganize tags and cleanup --- src/tags.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tags.rs b/src/tags.rs index a4e03f6..f0b2258 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -111,12 +111,12 @@ pub enum Tag(u16) unknown("A private or extension tag") { Threshholding = 263, // TODO add support XResolution = 282, YResolution = 283, - // JPEG TileWidth = 322, TileLength = 323, TileOffsets = 324, TileByteCounts = 325, SampleFormat = 339, + // JPEG JPEGTables = 347, // Advanced tags Predictor = 317, From 72474b569eac81ce35b3ac79d59c701dcd76fcbb Mon Sep 17 00:00:00 2001 From: ruffson Date: Fri, 25 Sep 2020 20:06:52 +0200 Subject: [PATCH 08/18] Add byte expected error and cleanup --- src/decoder/ifd.rs | 4 ++-- src/decoder/mod.rs | 1 - src/error.rs | 4 ++++ src/tags.rs | 5 ----- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/decoder/ifd.rs b/src/decoder/ifd.rs index f1daae7..2fbaee1 100644 --- a/src/decoder/ifd.rs +++ b/src/decoder/ifd.rs @@ -39,7 +39,7 @@ impl Value { match self { Byte(val) => Ok(val), val => Err(TiffError::FormatError( - TiffFormatError::UnsignedIntegerExpected(val), + TiffFormatError::ByteExpected(val), )), } } @@ -454,7 +454,7 @@ impl Entry { } }, (Type::UNDEFINED, n) => self.decode_offset(n, bo, limits, decoder, |decoder| { - Ok(Unsigned(u32::from(decoder.read_byte()?))) + Ok(Byte(u8::from(decoder.read_byte()?))) }), _ => Err(TiffError::UnsupportedError( TiffUnsupportedError::UnsupportedDataType, diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index c9ac8f5..a206d80 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -11,7 +11,6 @@ use tags::{CompressionMethod, PhotometricInterpretation, Predictor, SampleFormat use self::stream::{ ByteOrder, DeflateReader, EndianReader, LZWReader, PackBitsReader, SmartReader, JpegReader }; -use tags::{CompressionMethod, PhotometricInterpretation, Predictor, Tag, Type}; pub mod ifd; mod stream; diff --git a/src/error.rs b/src/error.rs index 5ace43c..2154292 100644 --- a/src/error.rs +++ b/src/error.rs @@ -45,6 +45,7 @@ pub enum TiffFormatError { InvalidTagValueType(Tag), RequiredTagNotFound(Tag), UnknownPredictor(u16), + ByteExpected(Value), UnsignedIntegerExpected(Value), SignedIntegerExpected(Value), InflateError(InflateError), @@ -69,6 +70,9 @@ impl fmt::Display for TiffFormatError { UnknownPredictor(ref predictor) => { write!(fmt, "Unknown predictor “{}” encountered", predictor) } + ByteExpected(ref val) => { + write!(fmt, "Expected byte, {:?} found.", val) + } UnsignedIntegerExpected(ref val) => { write!(fmt, "Expected unsigned integer, {:?} found.", val) } diff --git a/src/tags.rs b/src/tags.rs index f0b2258..2741725 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -111,11 +111,6 @@ pub enum Tag(u16) unknown("A private or extension tag") { Threshholding = 263, // TODO add support XResolution = 282, YResolution = 283, - TileWidth = 322, - TileLength = 323, - TileOffsets = 324, - TileByteCounts = 325, - SampleFormat = 339, // JPEG JPEGTables = 347, // Advanced tags From 5fd0534ea272d107eacb67a58b07f6bd63834fbb Mon Sep 17 00:00:00 2001 From: ruffson Date: Sat, 26 Sep 2020 12:23:40 +0200 Subject: [PATCH 09/18] Fix error handling --- src/decoder/mod.rs | 44 +++++++++++++++++++++++++++----------------- src/error.rs | 4 ++++ 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index a206d80..f741d90 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -9,7 +9,7 @@ use self::ifd::Directory; use tags::{CompressionMethod, PhotometricInterpretation, Predictor, SampleFormat, Tag, Type}; use self::stream::{ - ByteOrder, DeflateReader, EndianReader, LZWReader, PackBitsReader, SmartReader, JpegReader + ByteOrder, DeflateReader, EndianReader, JpegReader, LZWReader, PackBitsReader, SmartReader, }; pub mod ifd; @@ -956,18 +956,21 @@ impl Decoder { Ok(()) } - pub fn read_jpeg(&mut self, read_strip_wise: bool) -> TiffResult { - + pub fn read_jpeg(&mut self) -> TiffResult { let offsets: Vec; let bytes: Vec; let jpeg_tables: Vec = self.get_tag_u8_vec(Tag::JPEGTables)?; - if read_strip_wise { - offsets = self.get_tag_u32_vec(Tag::StripOffsets)?; - bytes = self.get_tag_u32_vec(Tag::StripByteCounts)?; - } else { - offsets = self.get_tag_u32_vec(Tag::TileOffsets)?; - bytes = self.get_tag_u32_vec(Tag::TileByteCounts)?; + match self.find_tag(Tag::TileOffsets) { + Ok(None) => { + offsets = self.get_tag_u32_vec(Tag::StripOffsets)?; + bytes = self.get_tag_u32_vec(Tag::StripByteCounts)?; + } + Ok(_) => { + offsets = self.get_tag_u32_vec(Tag::TileOffsets)?; + bytes = self.get_tag_u32_vec(Tag::TileByteCounts)?; + } + Err(e) => return Err(e), } let mut res_img = Vec::with_capacity(offsets[0] as usize); @@ -978,10 +981,21 @@ impl Decoder { let mut decoder = jpeg::Decoder::new(jpeg_reader); match decoder.decode() { - Err(e) => { - panic!("Error when reading jpeg tiles: {}", e); - } Ok(mut val) => res_img.append(&mut val), + Err(e) => { + return match e { + jpeg::Error::Io(io_err) => Err(TiffError::IoError(io_err)), + jpeg::Error::Format(fmt_err) => { + Err(TiffError::FormatError(TiffFormatError::Format(fmt_err))) + } + jpeg::Error::Unsupported(_) => Err(TiffError::UnsupportedError( + TiffUnsupportedError::UnknownInterpretation, + )), + jpeg::Error::Internal(_) => Err(TiffError::UnsupportedError( + TiffUnsupportedError::UnknownInterpretation, + )), + } + } } } @@ -1110,12 +1124,8 @@ impl Decoder { /// Decodes the entire image and return it as a Vector pub fn read_image(&mut self) -> TiffResult { - if self.compression_method == CompressionMethod::ModernJPEG { - match self.find_tag(Tag::TileOffsets) { - Ok(None) | Err(_) => return self.read_jpeg(true), - Ok(_) => return self.read_jpeg(false), - } + return self.read_jpeg(); } self.initialize_strip_decoder()?; diff --git a/src/error.rs b/src/error.rs index 2154292..8bef943 100644 --- a/src/error.rs +++ b/src/error.rs @@ -49,6 +49,7 @@ pub enum TiffFormatError { UnsignedIntegerExpected(Value), SignedIntegerExpected(Value), InflateError(InflateError), + Format(String), #[doc(hidden)] /// Do not match against this variant. It may get removed. __NonExhaustive, @@ -80,6 +81,9 @@ impl fmt::Display for TiffFormatError { write!(fmt, "Expected signed integer, {:?} found.", val) } InflateError(_) => write!(fmt, "Failed to decode inflate data."), + Format(ref val) => { + write!(fmt, "Invalid format: {:?}.", val) + } __NonExhaustive => unreachable!(), } } From 41050c14ed520c983937af7c85f62d3dc395972a Mon Sep 17 00:00:00 2001 From: ruffson Date: Sat, 26 Sep 2020 12:38:02 +0200 Subject: [PATCH 10/18] Change accesibility of JpegReader --- src/decoder/stream.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/decoder/stream.rs b/src/decoder/stream.rs index 7df3bf8..066786d 100644 --- a/src/decoder/stream.rs +++ b/src/decoder/stream.rs @@ -322,7 +322,7 @@ impl EndianReader for LZWReader { /// ## JPEG Reader (for "new-style" JPEG format (TIFF compression tag 7)) /// -pub struct JpegReader { +pub(crate) struct JpegReader { buffer: io::Cursor>, byte_order: ByteOrder, // for jpeg image data always ..., } From 35ea719d9e0fa21f0d6bbbb2e2958fbbd4d7d89c Mon Sep 17 00:00:00 2001 From: ruffson Date: Sat, 26 Sep 2020 13:44:53 +0200 Subject: [PATCH 11/18] Remove get_all_tags() --- src/decoder/mod.rs | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index f741d90..6e98275 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -712,32 +712,6 @@ impl Decoder { } } - pub fn get_all_tags(&mut self) -> Vec<(Tag, ifd::Value)> { - let mut all_tags = Vec::new(); - - let dir = match &self.ifd { - Some(d) => d, - None => { - println!("No tags found"); - return all_tags; - } - }; - let keys = dir.keys().cloned().collect::>(); - // go through all tags - for key in keys { - let tag_value = match self.get_tag(key) { - Ok(val) => val, - _ => { - println!("Could not unwrap {:?}", key); - continue; - } - }; - all_tags.push((key, tag_value)); - } - - all_tags - } - /// Tries to retrieve a tag and convert it to the desired type. pub fn get_tag_u32(&mut self, tag: Tag) -> TiffResult { self.get_tag(tag)?.into_u32() From cb900819d9cb9996a9d44908eca97cb915598da8 Mon Sep 17 00:00:00 2001 From: ruffson Date: Sat, 26 Sep 2020 14:07:27 +0200 Subject: [PATCH 12/18] Remove tile processing and add error handling I removed the code that checked the tile attributes. Because I would rather later on PR something that works than a half-baked solution. --- src/decoder/mod.rs | 23 +++++++++++------------ src/error.rs | 4 ++++ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 6e98275..cda4d76 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -931,20 +931,19 @@ impl Decoder { } pub fn read_jpeg(&mut self) -> TiffResult { - let offsets: Vec; - let bytes: Vec; + let offsets = self.get_tag_u32_vec(Tag::StripOffsets)?; + let bytes = self.get_tag_u32_vec(Tag::StripByteCounts)?; let jpeg_tables: Vec = self.get_tag_u8_vec(Tag::JPEGTables)?; - match self.find_tag(Tag::TileOffsets) { - Ok(None) => { - offsets = self.get_tag_u32_vec(Tag::StripOffsets)?; - bytes = self.get_tag_u32_vec(Tag::StripByteCounts)?; - } - Ok(_) => { - offsets = self.get_tag_u32_vec(Tag::TileOffsets)?; - bytes = self.get_tag_u32_vec(Tag::TileByteCounts)?; - } - Err(e) => return Err(e), + if offsets.len() == 0 { + return Err(TiffError::FormatError(TiffFormatError::RequiredTagEmpty( + Tag::StripOffsets, + ))); + } + if offsets.len() != bytes.len() { + return Err(TiffError::FormatError(TiffFormatError::Format( + String::from("Size mismatch of StripOffsets and StripByteCounts"), + ))); } let mut res_img = Vec::with_capacity(offsets[0] as usize); diff --git a/src/error.rs b/src/error.rs index 8bef943..15e0e7e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -50,6 +50,7 @@ pub enum TiffFormatError { SignedIntegerExpected(Value), InflateError(InflateError), Format(String), + RequiredTagEmpty(Tag), #[doc(hidden)] /// Do not match against this variant. It may get removed. __NonExhaustive, @@ -84,6 +85,9 @@ impl fmt::Display for TiffFormatError { Format(ref val) => { write!(fmt, "Invalid format: {:?}.", val) } + RequiredTagEmpty(ref val) => { + write!(fmt, "Required tag {:?} was empty.", val) + } __NonExhaustive => unreachable!(), } } From 53aefea6a443d187c474c75196a44c234124c6f4 Mon Sep 17 00:00:00 2001 From: ruffson Date: Sat, 26 Sep 2020 14:14:09 +0200 Subject: [PATCH 13/18] Fix typos --- src/decoder/stream.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/decoder/stream.rs b/src/decoder/stream.rs index 066786d..6b77c3d 100644 --- a/src/decoder/stream.rs +++ b/src/decoder/stream.rs @@ -324,19 +324,18 @@ impl EndianReader for LZWReader { pub(crate) struct JpegReader { buffer: io::Cursor>, - byte_order: ByteOrder, // for jpeg image data always ..., + byte_order: ByteOrder, } -// Only tested with qtables in jpegtables, but it contain both qtables and huffman tables or either impl JpegReader { /// Constructs new JpegReader wrapping a SmartReader. - /// Because Jpeg compression in TIFF allows to save quantization and/or huffman tables in one + /// Because JPEG compression in TIFF allows to save quantization and/or huffman tables in one /// central loacation, the constructor accepts this data as `jpeg_tables` here containing either - /// both. + /// or both. /// These `jpeg_tables` are simply prepended to the remaining jpeg image data. - /// Because these jpegtables start with a `SOI` (HEX: `0xFFD8`) or __start of image__ marker - /// which is also at the beginning of the remaining jpeg image data and would - /// confuse the jpeg renderer, one of these has to be taken off. In this case the first two - /// bytes of the remaining jpeg data is removed because this follows `jpeg_tables`. + /// Because these `jpeg_tables` start with a `SOI` (HEX: `0xFFD8`) or __start of image__ marker + /// which is also at the beginning of the remaining JPEG image data and would + /// confuse the JPEG renderer, one of these has to be taken off. In this case the first two + /// bytes of the remaining JPEG data is removed because it follows `jpeg_tables`. /// Similary, `jpeg_tables` ends with a `EOI` (HEX: `0xFFD9`) or __end of image__ marker, /// this has to be removed as well (last two bytes of `jpeg_tables`). From cb5319c426aa9a94f56299b7d7b206f4f28577f6 Mon Sep 17 00:00:00 2001 From: ruffson Date: Sat, 26 Sep 2020 14:35:06 +0200 Subject: [PATCH 14/18] Deal with empty jpeg_tables --- src/decoder/ifd.rs | 10 ++++------ src/decoder/mod.rs | 7 ++++++- src/decoder/stream.rs | 28 +++++++++++++++++++--------- src/error.rs | 12 +++--------- 4 files changed, 32 insertions(+), 25 deletions(-) diff --git a/src/decoder/ifd.rs b/src/decoder/ifd.rs index 2fbaee1..ced9a81 100644 --- a/src/decoder/ifd.rs +++ b/src/decoder/ifd.rs @@ -10,8 +10,8 @@ use tags::{Tag, Type}; use {TiffError, TiffFormatError, TiffResult, TiffUnsupportedError}; use self::Value::{ - Ascii, Byte, Double, Float, List, Rational, RationalBig, SRational, SRationalBig, Signed, SignedBig, - Unsigned, UnsignedBig, + Ascii, Byte, Double, Float, List, Rational, RationalBig, SRational, SRationalBig, Signed, + SignedBig, Unsigned, UnsignedBig, }; #[allow(unused_qualifications)] @@ -38,9 +38,7 @@ impl Value { pub fn into_u8(self) -> TiffResult { match self { Byte(val) => Ok(val), - val => Err(TiffError::FormatError( - TiffFormatError::ByteExpected(val), - )), + val => Err(TiffError::FormatError(TiffFormatError::ByteExpected(val))), } } @@ -452,7 +450,7 @@ impl Entry { let string = decoder.read_string(n)?; Ok(Ascii(string)) } - }, + } (Type::UNDEFINED, n) => self.decode_offset(n, bo, limits, decoder, |decoder| { Ok(Byte(u8::from(decoder.read_byte()?))) }), diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index cda4d76..b552cd6 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -933,7 +933,12 @@ impl Decoder { pub fn read_jpeg(&mut self) -> TiffResult { let offsets = self.get_tag_u32_vec(Tag::StripOffsets)?; let bytes = self.get_tag_u32_vec(Tag::StripByteCounts)?; - let jpeg_tables: Vec = self.get_tag_u8_vec(Tag::JPEGTables)?; + + let jpeg_tables: Option> = match self.find_tag(Tag::JPEGTables) { + Ok(None) => None, + Ok(_) => Some(self.get_tag_u8_vec(Tag::JPEGTables)?), + Err(e) => return Err(e), + }; if offsets.len() == 0 { return Err(TiffError::FormatError(TiffFormatError::RequiredTagEmpty( diff --git a/src/decoder/stream.rs b/src/decoder/stream.rs index 6b77c3d..c538b94 100644 --- a/src/decoder/stream.rs +++ b/src/decoder/stream.rs @@ -329,7 +329,7 @@ pub(crate) struct JpegReader { impl JpegReader { /// Constructs new JpegReader wrapping a SmartReader. /// Because JPEG compression in TIFF allows to save quantization and/or huffman tables in one - /// central loacation, the constructor accepts this data as `jpeg_tables` here containing either + /// central location, the constructor accepts this data as `jpeg_tables` here containing either /// or both. /// These `jpeg_tables` are simply prepended to the remaining jpeg image data. /// Because these `jpeg_tables` start with a `SOI` (HEX: `0xFFD8`) or __start of image__ marker @@ -342,7 +342,7 @@ impl JpegReader { pub fn new( reader: &mut SmartReader, length: u32, - jpeg_tables: &Vec, + jpeg_tables: &Option>, ) -> io::Result where R: Read + Seek, @@ -353,15 +353,25 @@ impl JpegReader { let mut segment = vec![0; length as usize]; reader.read_exact(&mut segment[..])?; - let mut jpeg_data = jpeg_tables.clone(); - jpeg_data.truncate(jpeg_data.len() - 2); + match jpeg_tables { + Some(tables) => { + let mut jpeg_data = tables.clone(); + jpeg_data.truncate(jpeg_data.len() - 2); + jpeg_data.extend_from_slice(&mut segment[2..]); - jpeg_data.extend_from_slice(&mut segment[2..]); + Ok(JpegReader { + buffer: io::Cursor::new(jpeg_data), + byte_order: order, + }) + }, + None => { + Ok(JpegReader { + buffer: io::Cursor::new(segment), + byte_order: order, + }) + } + } - Ok(JpegReader { - buffer: io::Cursor::new(jpeg_data), - byte_order: order, - }) } } diff --git a/src/error.rs b/src/error.rs index 15e0e7e..51aef38 100644 --- a/src/error.rs +++ b/src/error.rs @@ -72,9 +72,7 @@ impl fmt::Display for TiffFormatError { UnknownPredictor(ref predictor) => { write!(fmt, "Unknown predictor “{}” encountered", predictor) } - ByteExpected(ref val) => { - write!(fmt, "Expected byte, {:?} found.", val) - } + ByteExpected(ref val) => write!(fmt, "Expected byte, {:?} found.", val), UnsignedIntegerExpected(ref val) => { write!(fmt, "Expected unsigned integer, {:?} found.", val) } @@ -82,12 +80,8 @@ impl fmt::Display for TiffFormatError { write!(fmt, "Expected signed integer, {:?} found.", val) } InflateError(_) => write!(fmt, "Failed to decode inflate data."), - Format(ref val) => { - write!(fmt, "Invalid format: {:?}.", val) - } - RequiredTagEmpty(ref val) => { - write!(fmt, "Required tag {:?} was empty.", val) - } + Format(ref val) => write!(fmt, "Invalid format: {:?}.", val), + RequiredTagEmpty(ref val) => write!(fmt, "Required tag {:?} was empty.", val), __NonExhaustive => unreachable!(), } } From 7c4ee96aeef69bc21e6a03df966fbb26188920fa Mon Sep 17 00:00:00 2001 From: ruffson Date: Sat, 26 Sep 2020 16:50:51 +0200 Subject: [PATCH 15/18] Check for size when reading strip bytes --- src/decoder/mod.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index b552cd6..ce5a36c 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -165,6 +165,9 @@ pub struct Limits { /// The maximum size of any ifd value in bytes, the default is /// 1MiB. pub ifd_value_size: usize, + /// Maximum size for intermediate buffer which may be used to limit the amount of data read per + /// segment even if the entire image is decoded at once. + pub intermediate_buffer_size: usize, /// The purpose of this is to prevent all the fields of the struct from /// being public, as this would make adding new fields a major version /// bump. @@ -175,6 +178,7 @@ impl Default for Limits { fn default() -> Limits { Limits { decoding_buffer_size: 256 * 1024 * 1024, + intermediate_buffer_size: 128 * 1024 * 1024, ifd_value_size: 1024 * 1024, _non_exhaustive: (), } @@ -954,6 +958,11 @@ impl Decoder { let mut res_img = Vec::with_capacity(offsets[0] as usize); for (idx, offset) in offsets.iter().enumerate() { + + if bytes[idx] as usize > self.limits.intermediate_buffer_size { + return Err(TiffError::LimitsExceeded); + } + self.goto_offset(*offset)?; let jpeg_reader = JpegReader::new(&mut self.reader, bytes[idx], &jpeg_tables)?; let mut decoder = jpeg::Decoder::new(jpeg_reader); From 6353f71e28a5367ed6d513106c358863ce691eac Mon Sep 17 00:00:00 2001 From: ruffson Date: Sat, 26 Sep 2020 17:14:17 +0200 Subject: [PATCH 16/18] Satisfy the borrow checker --- src/decoder/stream.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/decoder/stream.rs b/src/decoder/stream.rs index c538b94..022318b 100644 --- a/src/decoder/stream.rs +++ b/src/decoder/stream.rs @@ -356,7 +356,8 @@ impl JpegReader { match jpeg_tables { Some(tables) => { let mut jpeg_data = tables.clone(); - jpeg_data.truncate(jpeg_data.len() - 2); + let truncated_length = jpeg_data.len() - 2; + jpeg_data.truncate(truncated_length); jpeg_data.extend_from_slice(&mut segment[2..]); Ok(JpegReader { From d00ab0cc61e56a117af580e9ab4cb3793f6c14f7 Mon Sep 17 00:00:00 2001 From: ruffson Date: Sat, 26 Sep 2020 17:22:59 +0200 Subject: [PATCH 17/18] Fix formatting --- src/decoder/mod.rs | 1 - src/decoder/stream.rs | 11 ++++------- src/lib.rs | 2 +- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index ce5a36c..9c95bc5 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -958,7 +958,6 @@ impl Decoder { let mut res_img = Vec::with_capacity(offsets[0] as usize); for (idx, offset) in offsets.iter().enumerate() { - if bytes[idx] as usize > self.limits.intermediate_buffer_size { return Err(TiffError::LimitsExceeded); } diff --git a/src/decoder/stream.rs b/src/decoder/stream.rs index 022318b..327e6de 100644 --- a/src/decoder/stream.rs +++ b/src/decoder/stream.rs @@ -364,15 +364,12 @@ impl JpegReader { buffer: io::Cursor::new(jpeg_data), byte_order: order, }) - }, - None => { - Ok(JpegReader { - buffer: io::Cursor::new(segment), - byte_order: order, - }) } + None => Ok(JpegReader { + buffer: io::Cursor::new(segment), + byte_order: order, + }), } - } } diff --git a/src/lib.rs b/src/lib.rs index 4867d61..7de0f5e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,9 +6,9 @@ //! # Related Links //! * - The TIFF specification +extern crate jpeg; extern crate miniz_oxide; extern crate weezl; -extern crate jpeg; mod bytecast; pub mod decoder; From 6281360f10c74a964c031afcf5c5a57adf413b9d Mon Sep 17 00:00:00 2001 From: ruffson Date: Sat, 26 Sep 2020 18:45:58 +0200 Subject: [PATCH 18/18] Fix error case --- src/decoder/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 9c95bc5..4cc1bd7 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -950,9 +950,9 @@ impl Decoder { ))); } if offsets.len() != bytes.len() { - return Err(TiffError::FormatError(TiffFormatError::Format( - String::from("Size mismatch of StripOffsets and StripByteCounts"), - ))); + return Err(TiffError::FormatError( + TiffFormatError::InconsistentSizesEncountered, + )); } let mut res_img = Vec::with_capacity(offsets[0] as usize);