diff --git a/src/io/geotiff.rs b/src/io/geotiff.rs index d843321..48540e7 100644 --- a/src/io/geotiff.rs +++ b/src/io/geotiff.rs @@ -21,6 +21,25 @@ impl CogReader { Ok(Self { decoder }) } + /// Decode GeoTIFF image to an [`ndarray::Array`] + fn ndarray(&mut self) -> TiffResult> { + // Get image dimensions + let (width, height): (u32, u32) = self.decoder.dimensions()?; + + // Get image pixel data + let decode_result = self.decoder.read_image()?; + let image_data: Vec = match decode_result { + DecodingResult::F32(img_data) => img_data, + _ => unimplemented!("Data types other than float32 are not yet supported."), + }; + + // Put image pixel data into an ndarray + let vec_data = Array2::from_shape_vec((height as usize, width as usize), image_data) + .map_err(|_| TiffFormatError::InvalidDimensions(height, width))?; + + Ok(vec_data) + } + /// Affine transformation for 2D matrix extracted from TIFF tag metadata, used to transform /// image pixel (row, col) coordinates to and from geographic/projected (x, y) coordinates. /// @@ -76,17 +95,8 @@ pub fn read_geotiff(stream: R) -> TiffResult> { // Open TIFF stream with decoder let mut reader = CogReader::new(stream)?; - // Get image dimensions - let (width, height): (u32, u32) = reader.decoder.dimensions()?; - - // Get image pixel data - let DecodingResult::F32(img_data) = reader.decoder.read_image()? else { - panic!("Cannot read band data") - }; - - // Put image pixel data into an ndarray - let vec_data = Array2::from_shape_vec((height as usize, width as usize), img_data) - .map_err(|_| TiffFormatError::InvalidDimensions(height, width))?; + // Decode TIFF into ndarray + let vec_data: Array2 = reader.ndarray()?; Ok(vec_data) } @@ -96,6 +106,7 @@ mod tests { use std::io::{Cursor, Seek, SeekFrom}; use geo::AffineTransform; + use ndarray::array; use object_store::parse_url; use tempfile::tempfile; use tiff::encoder::{colortype, TiffEncoder}; @@ -131,6 +142,23 @@ mod tests { assert_eq!(arr.mean(), Some(14.0)); } + #[tokio::test] + async fn test_cogreader_ndarray() { + let cog_url: &str = "https://github.com/rasterio/rasterio/raw/1.3.9/tests/data/float32.tif"; + let tif_url = Url::parse(cog_url).unwrap(); + let (store, location) = parse_url(&tif_url).unwrap(); + + let result = store.get(&location).await.unwrap(); + let bytes = result.bytes().await.unwrap(); + let stream = Cursor::new(bytes); + + let mut reader = CogReader::new(stream).unwrap(); + let array = reader.ndarray().unwrap(); + + assert_eq!(array.shape(), [2, 3]); + assert_eq!(array, array![[1.41, 1.23, 0.78], [0.32, -0.23, -1.88]]) + } + #[tokio::test] async fn test_cogreader_transform() { let cog_url: &str =