From fca4e1f88a877b942525dad572d5bc7af40e7b03 Mon Sep 17 00:00:00 2001 From: Andrew Champion Date: Tue, 10 Dec 2019 18:46:12 +0000 Subject: [PATCH] Support 32-bit grayscale decoding --- src/decoder/mod.rs | 38 +++++++++++++++++++++++++++++- src/decoder/stream.rs | 12 ++++++++++ tests/decode_images.rs | 20 ++++++++++++++++ tests/images/gradient-1c-32b.tiff | Bin 0 -> 1341 bytes 4 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 tests/images/gradient-1c-32b.tiff diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index a3aff91..cfdbbe0 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -19,6 +19,8 @@ pub enum DecodingResult { U8(Vec), /// A vector of unsigned words U16(Vec), + /// A vector of 32 bit unsigned ints + U32(Vec), } impl DecodingResult { @@ -38,10 +40,19 @@ impl DecodingResult { } } + fn new_u32(size: usize, limits: &Limits) -> TiffResult { + if size > limits.decoding_buffer_size / 4 { + Err(TiffError::LimitsExceeded) + } else { + Ok(DecodingResult::U32(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..]), } } } @@ -52,6 +63,8 @@ pub enum DecodingBuffer<'a> { U8(&'a mut [u8]), /// A slice of unsigned words U16(&'a mut [u16]), + /// A slice of 32 bit unsigned ints + U32(&'a mut [u32]), } impl<'a> DecodingBuffer<'a> { @@ -59,6 +72,7 @@ impl<'a> DecodingBuffer<'a> { match *self { DecodingBuffer::U8(ref buf) => buf.len(), DecodingBuffer::U16(ref buf) => buf.len(), + DecodingBuffer::U32(ref buf) => buf.len(), } } @@ -66,6 +80,7 @@ impl<'a> DecodingBuffer<'a> { match *self { DecodingBuffer::U8(_) => 1, DecodingBuffer::U16(_) => 2, + DecodingBuffer::U32(_) => 4, } } @@ -76,6 +91,7 @@ impl<'a> DecodingBuffer<'a> { match *self { DecodingBuffer::U8(ref mut buf) => DecodingBuffer::U8(buf), DecodingBuffer::U16(ref mut buf) => DecodingBuffer::U16(buf), + DecodingBuffer::U32(ref mut buf) => DecodingBuffer::U32(buf), } } } @@ -233,6 +249,12 @@ impl Wrapping for u16 { } } +impl Wrapping for u32 { + fn wrapping_add(&self, other: Self) -> Self { + u32::wrapping_add(*self, other) + } +} + fn rev_hpredict_nsamp(image: &mut [T], size: (u32, u32), samples: usize) where T: Copy + Wrapping, @@ -250,7 +272,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) => 1, + ColorType::Gray(8) | ColorType::Gray(16) | ColorType::Gray(32) => 1, ColorType::RGB(8) | ColorType::RGB(16) => 3, ColorType::RGBA(8) | ColorType::RGBA(16) | ColorType::CMYK(8) => 4, _ => { @@ -266,6 +288,9 @@ fn rev_hpredict(image: DecodingBuffer, size: (u32, u32), color_type: ColorType) DecodingBuffer::U16(buf) => { rev_hpredict_nsamp(buf, size, samples); } + DecodingBuffer::U32(buf) => { + rev_hpredict_nsamp(buf, size, samples); + } } Ok(()) } @@ -659,6 +684,15 @@ impl Decoder { reader.read_u16_into(&mut buffer[..bytes / 2])?; bytes / 2 } + (ColorType::Gray(32), DecodingBuffer::U32(ref mut buffer)) => { + reader.read_u32_into(&mut buffer[..bytes / 4])?; + if self.photometric_interpretation == PhotometricInterpretation::WhiteIsZero { + for datum in buffer[..bytes / 4].iter_mut() { + *datum = 0xffff_ffff - *datum + } + } + bytes / 4 + } (ColorType::Gray(16), DecodingBuffer::U16(ref mut buffer)) => { reader.read_u16_into(&mut buffer[..bytes / 2])?; if self.photometric_interpretation == PhotometricInterpretation::WhiteIsZero { @@ -806,6 +840,7 @@ impl Decoder { let mut result = match self.bits_per_sample.iter().cloned().max().unwrap_or(8) { 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 => { return Err(TiffError::UnsupportedError( TiffUnsupportedError::UnsupportedBitsPerChannel(n), @@ -834,6 +869,7 @@ impl Decoder { let mut result = match self.bits_per_sample.iter().cloned().max().unwrap_or(8) { 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 => { return Err(TiffError::UnsupportedError( TiffUnsupportedError::UnsupportedBitsPerChannel(n), diff --git a/src/decoder/stream.rs b/src/decoder/stream.rs index fe5d20c..997e096 100644 --- a/src/decoder/stream.rs +++ b/src/decoder/stream.rs @@ -59,6 +59,18 @@ pub trait EndianReader: Read { } } + #[inline(always)] + fn read_u32_into(&mut self, buffer: &mut [u32]) -> Result<(), io::Error> { + match self.byte_order() { + ByteOrder::LittleEndian => { + ::read_u32_into::(self, buffer) + } + ByteOrder::BigEndian => { + ::read_u32_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 7c91988..9a6076a 100644 --- a/tests/decode_images.rs +++ b/tests/decode_images.rs @@ -64,6 +64,26 @@ fn test_gray_u16() { } } +#[test] +fn test_gray_u32() { + let img_file = + File::open("./tests/images/gradient-1c-32b.tiff").expect("Cannot find test image!"); + let mut decoder = Decoder::new(img_file).expect("Cannot create decoder"); + assert_eq!(decoder.colortype().unwrap(), ColorType::Gray(32)); + let img_res = decoder.read_image().unwrap(); + if let DecodingResult::U32(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-32b.tiff b/tests/images/gradient-1c-32b.tiff new file mode 100644 index 0000000000000000000000000000000000000000..3b05740b7eff3ee0dfa47ae20a17cef01870a4b7 GIT binary patch literal 1341 zcmYk6dtA&}7{=e}wz)1LikQVFZOJyWHkU4143b@hkeQ~MhDNh9Q7*HeGqpuDWhhax zX_Ky!$)(%|r8MN8+ZMa+l1MJQF1wq@k57Nh`Qx1L^PcB<-_QBy2!+mMZ9&wU;z@OT z6g=-mDP|{DRG4oy7FqPk&9;2|MrPGoE%>aD|88qTrE52D=hW_eT|f_!u&k%y{hD4m zx`(|*ovEK2q_RGSjXV4DgO1sVMy%^6GJ5wHof$JgbmoGs$T4>y|3%uMoWcusqP3a! ze9y|k{6q2~IZcHQ{F>0AqKW5*F;ym?`NV!fC3(Zy>ZB2LOFxpC9sQD}pLV43x=~a* z)rs}rHkw*aI8#B{S8Tq)g@sITWi1Y4NVUt2C7&Nld+NVtHXZIPs7XMQhH>QJ=)pAk z<5_&dHx%4BfktV*C5?|K70;YVhKxyU_?F4ct78gPMR>7ERo<-ME+3X&>&vV%r;@SO zkEG4tQN4B=J9%q5J!zc50@8%cB621>Hf|QJPnpeZI{m4aeh#~>4q%%4xpcq$duo09 z16fPvQG4us78kyNiV6aWSG17LDO$v0jf?55I*7dwT*6$NmeNf1GB$8aFsoE9Ct;F^ zjW{4?7du0U=1AD7h)^~uEsQo-h0}I}l%{NoAls`l)>*WIUI|yy&F*sYZk4k{zg4WM zIf}f*3MyInBRM`&lBPgK&c)GG*sz+?D%Q~E>oLSjjHQGdYpK0u9aUUjPY3lIsLfYR z+Q&b^#gd_PFhg6i2JLxq2sjmwcYZ%3>0knqeG{>*yYPeW#0I+hLDfkoLFIH2B%HjiCUmt>+KFbgdi z*;smMH^!da16AHH5GZpX-M1HwA-PD7{}qPWdAL%(4|5~(QC+(qGLHht6ou%SR0N0l z#qgM3g0YFE$WJ_g)1_swk3R^OSq|$>hj6c(9*Ny6uugCoMxFE3hrTiW>bjSe?BNN#PAxmfeIts}YVaw{UOk zZ49ctgQ23k5Zt|o$dSKcNnjJ~4mBg+=|0W}K7cXdcLa?31G#Z6a1Qwsi--M%Y3m#4T>)b@4}S*2R2| z%}wf7Cfti>Mx(j=*W6Fin`5pU@hyq^@+>~}wC1#piGP3z+jcSIJOjJ@#PzY~S$@hs zSmmtXX4=`xqN(+$?3L06{b|VNg~8@g)C~7*v&6Y zwK6(N;U;hoQAn0cmEyHyqGjRXL{pVv;^?qYevB+Sf