Skip to content

Commit

Permalink
✨ Implement reading of GeoTIFF from remote url via object_store
Browse files Browse the repository at this point in the history
Allow passing remote URLs to the read_geotiff_py function. URLs are handled via object_store's parse_url function. Data is read asynchronously into an in-memory buffer (within a tokio runtime), and passed into the synchronous io::geotiff::read_geotiff function. Also added a short example in the Python docstring on how this can be used.
  • Loading branch information
weiji14 committed Mar 1, 2024
1 parent 6cc8f4b commit 33faafb
Showing 1 changed file with 30 additions and 5 deletions.
35 changes: 30 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,59 @@
/// Modules for handling Input/Output of GeoTIFF data
pub mod io;

use std::fs::File;
use std::io::Cursor;

use ndarray::Dim;
use numpy::{PyArray, ToPyArray};
use object_store::{parse_url, ObjectStore};
use pyo3::prelude::{pyfunction, pymodule, PyModule, PyResult, Python};
use pyo3::wrap_pyfunction;
use tokio;
use url::Url;

/// Read a GeoTIFF file from a path on disk into an ndarray
///
/// Parameters
/// ----------
/// path : str
/// The path to the file.
/// The path to the file, or a url to a remote file.
///
/// Returns
/// -------
/// array : np.ndarray
/// 2D array containing the GeoTIFF pixel data.
///
/// Examples
/// --------
/// from cog3pio import read_geotiff
///
/// array = read_geotiff("https://github.com/pka/georaster/raw/v0.1.0/data/tiff/float32.tif")
/// assert array.shape == (20, 20)
#[pyfunction]
#[pyo3(name = "read_geotiff")]
fn read_geotiff_py<'py>(
path: &str,
py: Python<'py>,
) -> PyResult<&'py PyArray<f32, Dim<[usize; 2]>>> {
// Open TIFF file from path
let file = File::open(path).expect("Cannot find GeoTIFF file");
// Initialize async runtime
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()?;

// Get TIFF file stream asynchronously
let stream = runtime.block_on(async {
// Parse URL
let url = Url::parse(path).expect(&format!("Cannot parse path: {path}"));
let (store, location) = parse_url(&url).expect(&format!("Cannot parse url: {url}"));

// Return cursor to in-memory buffer
let result = store.get(&location).await.unwrap();
let bytes = result.bytes().await.unwrap();
Cursor::new(bytes)
});

// Get image pixel data as an ndarray
let vec_data = io::geotiff::read_geotiff(file).expect("Cannot read GeoTIFF");
let vec_data = io::geotiff::read_geotiff(stream).expect("Cannot read GeoTIFF");
// Convert from ndarray (Rust) to numpy ndarray (Python)
Ok(vec_data.to_pyarray(py))
}
Expand Down

0 comments on commit 33faafb

Please sign in to comment.