From f4e985e0bdf6314ce5aba0e4ca7c59c96a4e35c9 Mon Sep 17 00:00:00 2001 From: Andrew Champion Date: Tue, 10 Dec 2019 19:37:46 +0000 Subject: [PATCH] Support 64-bit grayscale decoding --- src/decoder/mod.rs | 38 +++++++++++++++++++++++++++++- src/decoder/stream.rs | 21 +++++++++++++++++ tests/decode_images.rs | 20 ++++++++++++++++ tests/images/gradient-1c-64b.tiff | Bin 0 -> 2368 bytes 4 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 tests/images/gradient-1c-64b.tiff diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index d754b94..0b6719e 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -21,6 +21,8 @@ pub enum DecodingResult { U16(Vec), /// A vector of 32 bit unsigned ints U32(Vec), + /// A vector of 64 bit unsigned ints + U64(Vec), } impl DecodingResult { @@ -48,11 +50,20 @@ impl DecodingResult { } } + fn new_u64(size: usize, limits: &Limits) -> TiffResult { + if size > limits.decoding_buffer_size / 8 { + Err(TiffError::LimitsExceeded) + } else { + Ok(DecodingResult::U64(vec![0; size])) + } + } + pub fn as_buffer(&mut self, start: usize) -> DecodingBuffer { match *self { DecodingResult::U8(ref mut buf) => DecodingBuffer::U8(&mut buf[start..]), DecodingResult::U16(ref mut buf) => DecodingBuffer::U16(&mut buf[start..]), DecodingResult::U32(ref mut buf) => DecodingBuffer::U32(&mut buf[start..]), + DecodingResult::U64(ref mut buf) => DecodingBuffer::U64(&mut buf[start..]), } } } @@ -65,6 +76,8 @@ pub enum DecodingBuffer<'a> { U16(&'a mut [u16]), /// A slice of 32 bit unsigned ints U32(&'a mut [u32]), + /// A slice of 64 bit unsigned ints + U64(&'a mut [u64]), } impl<'a> DecodingBuffer<'a> { @@ -73,6 +86,7 @@ impl<'a> DecodingBuffer<'a> { DecodingBuffer::U8(ref buf) => buf.len(), DecodingBuffer::U16(ref buf) => buf.len(), DecodingBuffer::U32(ref buf) => buf.len(), + DecodingBuffer::U64(ref buf) => buf.len(), } } @@ -81,6 +95,7 @@ impl<'a> DecodingBuffer<'a> { DecodingBuffer::U8(_) => 1, DecodingBuffer::U16(_) => 2, DecodingBuffer::U32(_) => 4, + DecodingBuffer::U64(_) => 8, } } @@ -92,6 +107,7 @@ impl<'a> DecodingBuffer<'a> { DecodingBuffer::U8(ref mut buf) => DecodingBuffer::U8(buf), DecodingBuffer::U16(ref mut buf) => DecodingBuffer::U16(buf), DecodingBuffer::U32(ref mut buf) => DecodingBuffer::U32(buf), + DecodingBuffer::U64(ref mut buf) => DecodingBuffer::U64(buf), } } } @@ -255,6 +271,12 @@ impl Wrapping for u32 { } } +impl Wrapping for u64 { + fn wrapping_add(&self, other: Self) -> Self { + u64::wrapping_add(*self, other) + } +} + fn rev_hpredict_nsamp(image: &mut [T], size: (u32, u32), samples: usize) where T: Copy + Wrapping, @@ -272,7 +294,7 @@ where fn rev_hpredict(image: DecodingBuffer, size: (u32, u32), color_type: ColorType) -> TiffResult<()> { let samples = match color_type { - ColorType::Gray(8) | ColorType::Gray(16) | ColorType::Gray(32) => 1, + ColorType::Gray(8) | ColorType::Gray(16) | ColorType::Gray(32) | ColorType::Gray(64) => 1, ColorType::RGB(8) | ColorType::RGB(16) | ColorType::RGB(32) => 3, ColorType::RGBA(8) | ColorType::RGBA(16) | ColorType::RGBA(32) | ColorType::CMYK(8) => 4, _ => { @@ -291,6 +313,9 @@ fn rev_hpredict(image: DecodingBuffer, size: (u32, u32), color_type: ColorType) DecodingBuffer::U32(buf) => { rev_hpredict_nsamp(buf, size, samples); } + DecodingBuffer::U64(buf) => { + rev_hpredict_nsamp(buf, size, samples); + } } Ok(()) } @@ -695,6 +720,15 @@ impl Decoder { reader.read_u32_into(&mut buffer[..bytes / 4])?; bytes / 4 } + (ColorType::Gray(64), DecodingBuffer::U64(ref mut buffer)) => { + reader.read_u64_into(&mut buffer[..bytes / 8])?; + if self.photometric_interpretation == PhotometricInterpretation::WhiteIsZero { + for datum in buffer[..bytes / 8].iter_mut() { + *datum = 0xffff_ffff_ffff_ffff - *datum + } + } + bytes / 8 + } (ColorType::Gray(32), DecodingBuffer::U32(ref mut buffer)) => { reader.read_u32_into(&mut buffer[..bytes / 4])?; if self.photometric_interpretation == PhotometricInterpretation::WhiteIsZero { @@ -852,6 +886,7 @@ impl Decoder { n if n <= 8 => DecodingResult::new_u8(buffer_size, &self.limits)?, 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 => { return Err(TiffError::UnsupportedError( TiffUnsupportedError::UnsupportedBitsPerChannel(n), @@ -881,6 +916,7 @@ impl Decoder { n if n <= 8 => DecodingResult::new_u8(buffer_size, &self.limits)?, 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 => { return Err(TiffError::UnsupportedError( TiffUnsupportedError::UnsupportedBitsPerChannel(n), diff --git a/src/decoder/stream.rs b/src/decoder/stream.rs index 997e096..caf4e3c 100644 --- a/src/decoder/stream.rs +++ b/src/decoder/stream.rs @@ -71,6 +71,27 @@ pub trait EndianReader: Read { } } + /// Reads an u64 + #[inline(always)] + fn read_u64(&mut self) -> Result { + match self.byte_order() { + ByteOrder::LittleEndian => ::read_u64::(self), + ByteOrder::BigEndian => ::read_u64::(self), + } + } + + #[inline(always)] + fn read_u64_into(&mut self, buffer: &mut [u64]) -> Result<(), io::Error> { + match self.byte_order() { + ByteOrder::LittleEndian => { + ::read_u64_into::(self, buffer) + } + ByteOrder::BigEndian => { + ::read_u64_into::(self, buffer) + } + } + } + /// Reads an i32 #[inline(always)] fn read_i32(&mut self) -> Result { diff --git a/tests/decode_images.rs b/tests/decode_images.rs index 900606f..04ca7ef 100644 --- a/tests/decode_images.rs +++ b/tests/decode_images.rs @@ -84,6 +84,26 @@ fn test_gray_u32() { } } +#[test] +fn test_gray_u64() { + let img_file = + File::open("./tests/images/gradient-1c-64b.tiff").expect("Cannot find test image!"); + let mut decoder = Decoder::new(img_file).expect("Cannot create decoder"); + assert_eq!(decoder.colortype().unwrap(), ColorType::Gray(64)); + let img_res = decoder.read_image().unwrap(); + if let DecodingResult::U64(res) = img_res { + let mut res_sum: u64 = 0; + for x in res { + res_sum += x as u64; + } + + assert_eq!(res_sum, 549892913787); + } + else { + panic!("Wrong bit depth") + } +} + #[test] fn test_rgb_u16() { let img_file = File::open("./tests/images/rgb-3c-16b.tiff").expect("Cannot find test image!"); diff --git a/tests/images/gradient-1c-64b.tiff b/tests/images/gradient-1c-64b.tiff new file mode 100644 index 0000000000000000000000000000000000000000..43dec0c21fb2d793f4a553e288688e47db02a84c GIT binary patch literal 2368 zcmbukED(M6P~SX$Cm zQZD6oq?97}+*WLDBw8-pu&wNT-={rK&;H$cp5J+WKcDaS_x=6O`90@2JDW@NBoaw) zNr$AHM5-R~l6H>Og|u@l=Cq{Rtg%;*wL8b6*X=TXN2(#(aZ<$`j8xRZVY)(%~*23wsGj* zU`6j!Hy({lt?9$EY%n77BYMyJ2{Hif>--;O+~ z%pUvia=@f2N7PN3DwNb#IiX+UCs-3ZO{hG1b2|BP{S2~eqBC|2n2E>6&tg6_ZZ^4J zy9>Ej@f`9kg)4^D%%#6q^eHw!`3&`Z=3#5de4#Sj_j7V?wi`-w7tqhiU5FvIi|ET0 z?&J=)#c0{Egnp*NgFI-9Czh^UO79#kBab-Xg%{er=_PY~$fx|5;iSan^qb3kal6V7 zr)=^^{VQ^zvORYN`GxZrc%w%k+Bc&z%IQmyl?{zw(c5_iVg7=z(e&X;49gBi^So7< zQ@0uuOV;4#Yim&&6@ro1H9zgvruF2KOQCqMcmuXLYW`MYAAKY88w(vJ77WqY5)(#l z%?wA^QxW*u>069G7>O~CQMfUCBUZRo3TGegAw&ED9o)wF-c8z%f@#Hs| zTXCmT0!~ZVhRJ%{aYt4nri3S<$Iuj* z7@YYXTCGe+zkPeL-a7+hBECn}>`c5|v=8U{XJJLvew15hYYfW4p3%8zG(Qimr|09C zr~=H2I)JAO3ehm)ASzReP;b*AyxYAPqk5F!daJ`|v-AjF-G3C54Ugfo+@&ju-H<=|z-=)uF@TOQXu(apPcKcQ+NZ5Q|r;x;wIkR zdJ6|v-Ns?EJ7{(1E(VPJ0T;V9puwR=%rd)&=iKgNZRC&WI_f9P2ya4j@1Jqe@LzCR z=mXqd`w+bhno%D22%p-upq<}iY+mvN?}xNvtoyI16V!(FE1qKfnrC=4^*K(qe1Ut9 w{D!d}zoXpd53E}I5>w4yVUq1@oEP{f#(MsRx8wfS%