diff --git a/src/decoder/image.rs b/src/decoder/image.rs index 4a1d881c..af206787 100644 --- a/src/decoder/image.rs +++ b/src/decoder/image.rs @@ -346,14 +346,19 @@ impl Image { ), )), }, - PhotometricInterpretation::BlackIsZero | PhotometricInterpretation::WhiteIsZero - if self.samples == 1 => - { - Ok(ColorType::Gray(self.bits_per_sample)) + PhotometricInterpretation::BlackIsZero | PhotometricInterpretation::WhiteIsZero => { + match self.samples { + 1 => Ok(ColorType::Gray(self.bits_per_sample)), + _ => Ok(ColorType::Multiband { + bit_depth: self.bits_per_sample, + num_samples: self.samples, + }), + } } - // TODO: this is bad we should not fail at this point - _ => Err(TiffError::UnsupportedError( + PhotometricInterpretation::RGBPalette + | PhotometricInterpretation::TransparencyMask + | PhotometricInterpretation::CIELab => Err(TiffError::UnsupportedError( TiffUnsupportedError::InterpretationWithBits( self.photometric_interpretation, vec![self.bits_per_sample; self.samples as usize], @@ -555,13 +560,26 @@ impl Image { | (ColorType::CMYK(n), _) | (ColorType::YCbCr(n), _) | (ColorType::Gray(n), _) - if usize::from(n) == buffer.byte_len() * 8 => {} - (ColorType::Gray(n), DecodingBuffer::U8(_)) if n < 8 => match self.predictor { + | ( + ColorType::Multiband { + bit_depth: n, + num_samples: _, + }, + _, + ) if usize::from(n) == buffer.byte_len() * 8 => {} + ( + ColorType::Gray(n) + | ColorType::Multiband { + bit_depth: n, + num_samples: _, + }, + DecodingBuffer::U8(_), + ) if n < 8 => match self.predictor { Predictor::None => {} Predictor::Horizontal => { return Err(TiffError::UnsupportedError( TiffUnsupportedError::HorizontalPredictor(color_type), - )) + )); } Predictor::FloatingPoint => { return Err(TiffError::UnsupportedError( @@ -572,7 +590,7 @@ impl Image { (type_, _) => { return Err(TiffError::UnsupportedError( TiffUnsupportedError::UnsupportedColorType(type_), - )) + )); } } diff --git a/src/lib.rs b/src/lib.rs index 8f23f35e..1940723a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,4 +40,7 @@ pub enum ColorType { /// Pixel is YCbCr YCbCr(u8), + + /// Pixel has multiple bands/channels + Multiband { bit_depth: u8, num_samples: u16 }, } diff --git a/tests/decode_geotiff_images.rs b/tests/decode_geotiff_images.rs new file mode 100644 index 00000000..92ef7482 --- /dev/null +++ b/tests/decode_geotiff_images.rs @@ -0,0 +1,63 @@ +extern crate tiff; + +use tiff::decoder::{Decoder, DecodingResult}; +use tiff::tags::Tag; +use tiff::ColorType; + +use std::fs::File; +use std::path::PathBuf; + +const TEST_IMAGE_DIR: &str = "./tests/images"; + +#[test] +fn test_geo_tiff() { + let filenames = ["geo-5b.tif"]; + for filename in filenames.iter() { + let path = PathBuf::from(TEST_IMAGE_DIR).join(filename); + let img_file = File::open(path).expect("Cannot find test image!"); + let mut decoder = Decoder::new(img_file).expect("Cannot create decoder"); + decoder = decoder.with_limits(tiff::decoder::Limits::unlimited()); + + assert_eq!( + decoder.dimensions().expect("Cannot get dimensions"), + (10, 10) + ); + assert_eq!( + decoder.colortype().expect("Cannot get colortype"), + ColorType::Multiband { + bit_depth: 16, + num_samples: 5 + } + ); + assert_eq!( + decoder + .get_tag_u64(Tag::StripOffsets) + .expect("Cannot get StripOffsets"), + 418 + ); + assert_eq!( + decoder + .get_tag_u64(Tag::RowsPerStrip) + .expect("Cannot get RowsPerStrip"), + 10 + ); + assert_eq!( + decoder + .get_tag_u64(Tag::StripByteCounts) + .expect("Cannot get StripByteCounts"), + 1000 + ); + assert_eq!( + decoder + .get_tag(Tag::ModelPixelScaleTag) + .expect("Cannot get pixel scale") + .into_f64_vec() + .expect("Cannot get pixel scale"), + vec![60.0, 60.0, 0.0] + ); + let DecodingResult::I16(data) = decoder.read_image().unwrap() else { + panic!("Cannot read band data") + }; + assert_eq!(data.len(), 500); + } +} diff --git a/tests/images/geo-5b.tif b/tests/images/geo-5b.tif new file mode 100644 index 00000000..f52f4500 Binary files /dev/null and b/tests/images/geo-5b.tif differ