terrio
Pure-Rust geospatial raster, vector and point cloud data I/O.
Documentation: https://terrio.opengeos.org
terrio aims to read, write, convert and reproject the geospatial formats most workflows use, without C dependencies, so that it builds anywhere Rust does, including WebAssembly.
Status: early development. Reading, writing and converting work; the processing operations are in progress. See ROADMAP.md.
terrio builds on the pure-Rust format libraries of
whitebox_next_gen (wbraster, wbvector,
wbprojection) and adds format detection, remote and archived inputs, a GeoTIFF reader built on
the tiff crate, fixes for what the format libraries miss, and
GDAL-style operations.
Coordinate transformations match GDAL's: terrio carries the EPSG CRSs with the coordinate
operations GDAL uses for them (generated from GDAL and PROJ by scripts/gen_epsg_table.py) and
pure-Rust ports of the projections they need. For each of the 6,354 EPSG geographic and projected
CRSs GDAL 3.12 transforms, transformations from and to WGS 84 agree with GDAL's within a
centimetre, and 99 % of a sample of transformations between two CRSs within a metre (see
crates/terrio/tests/epsg_accuracy.rs).
Command line
Install the terrio command, a standalone binary, with:
|
pip install terrio installs it too, and cargo install terrio-cli builds it from source (see
Installation).
# Point clouds: LAS 1.0-1.4 (formats 0-10, extra bytes, waveforms), LAZ, COPC and EPT (read in
# place, local or remote), PLY, E57; files larger than memory converted in chunks
terrio mcp serves the commands to AI agents (Claude Code, Claude Desktop, Cursor, VS Code) over
the Model Context Protocol: claude mcp add terrio -- terrio mcp (see
AI Agents).
Library
let ds = open?;
println!;
// Cloud Optimized GeoTIFFs are read in place: opening fetches the headers, and a window read
// fetches only the tiles it needs, with HTTP range requests.
let mut cog = open_raster_lazy?;
let options = WindowOptions ;
let window = cog.read_window?;
# Ok::
Remote reads are configured with environment variables: AWS_ACCESS_KEY_ID,
AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN, AWS_PROFILE, AWS_REGION, AWS_NO_SIGN_REQUEST
and AWS_S3_ENDPOINT for S3; AZURE_STORAGE_ACCOUNT and AZURE_STORAGE_SAS_TOKEN for Azure;
TERRIO_HTTP_TIMEOUT, TERRIO_HTTP_MAX_RETRY and TERRIO_HTTP_LOG (and more, see the http
module) for HTTP.
Datasets can also be opened from bytes and written to bytes (terrio::memory), for data
already in memory and for WebAssembly, which has no file system.
An optional GDAL backend (the gdal cargo feature, off by default and the only C dependency)
opens what terrio has no driver for (HDF4, GRIB, NITF and the rest of GDAL's formats)
into the same data model, and writes rasters with GDAL's drivers: terrio::open("GDAL:file.hdf"),
terrio info --driver gdal, or a plain path when terrio's own drivers cannot open it.
Every driver is on by default; each family of them is a cargo feature that can be turned off,
for a smaller dependency tree and WebAssembly module: parquet, remote (URLs and object
storage), netcdf-hdf5, sqlite (GeoPackage), tiles (MBTiles, PMTiles, MVT), avif, zarr,
jp2, flatgeobuf, osm, pointcloud, lerc and lzma. GeoTIFF and COG, the plain raster
and vector formats, the CRS engine and the operations are always built. A COG writer, say,
needs only:
= { = "0.3", = false, = ["geotiff"] }
See the features for what each one adds.
Point clouds are read into columns, one typed vector per dimension (terrio::pointcloud):
use ;
// A COPC file is read in place: only the octree nodes in the bounds, down to level 4, are fetched.
let mut lidar = open_points?;
let filter = PointFilter ;
let ground = lidar.read?;
let z = ground.coords.unwrap;
write_points?;
let options = GridOptions ;
let dtm = grid?; // a RasterDataset
# Ok::
LAZ compression comes from the pure-Rust laz crate (the codec of
laspy's lazrs backend); terrio reads and writes the LAS container, extra bytes, CRS records and
COPC octrees itself.
Python
=
= # a NumPy array of the raster's own dtype
, , ,
= # read in place
=
= .
, ,
= # Arrow PyCapsule interface, GeoArrow geometries
= # pyarrow, GeoPandas, Polars, GDAL layers...
=
, , ,
The operations (convert, translate, warp, mosaic, rasterize, polygonize, dem,
calc, proximity, sieve) take the command-line options as keyword arguments. See
python/README.md.
rasterio scripts run with an import change, import terrio.rio as rasterio: datasets, windows,
CRSs, features, warping, merging, masking and memory files follow rasterio's API, compared with
rasterio on real files. See Coming from rasterio.
terrio.xarray is rioxarray's API without GDAL (pip install "terrio[xarray]"):
terrio.xarray.open_rasterio and xr.open_dataset(path, engine="terrio") open rasters lazily
(remote COGs fetch only the tiles a window needs, chunked with dask), and the .terrio accessor
has rioxarray's .rio methods (clip_box, clip, reproject, reproject_match, pad_box,
to_raster...), compared with rioxarray on real files. See
xarray.
JavaScript
The terrio-js npm package is the library compiled to WebAssembly, for browsers and Node.js:
import init from "terrio-js";
await ;
const dem = ;
dem.; // the summary `terrio info --json` prints
const band = dem.; // a Float32Array, Uint8Array...
const roads = ;
const fgb = roads.;
const ground = ; // LAS, LAZ, COPC
ground.; // a Float64Array
See js/README.md for the formats available in WebAssembly.
Testing against GDAL
scripts/fetch_test_data.sh downloads real-world files (Natural Earth, USGS 3DEP, Sentinel-2,
NASA ECOSTRESS and OPERA products, and more) and derives copies in other formats with GDAL.
scripts/conformance.py runs every comparison below and writes the conformance report
(docs/conformance.md, per format and operation: cases identical to GDAL, within tolerance or
different):
The comparisons, one by one:
TERRIO_TEST_DATA=../terrio-data
# convert with terrio, compare GDAL's reading
# queries, grids and reprojection vs PDAL
&& TERRIO_TEST_DATA=../../terrio-data TERRIO_TEST_DATA=../terrio-data TERRIO_TEST_DATA=../terrio-data
# every EPSG CRS's transformations against GDAL's
Layout
| Path | Contents |
|---|---|
crates/terrio |
The library |
crates/terrio-cli |
The terrio command-line tool |
python |
Python bindings (PyO3, NumPy), the terrio package on PyPI |
js |
WebAssembly bindings (wasm-bindgen), the terrio package on npm |
See ROADMAP.md for what is planned and in what order.
Acknowledgements
terrio builds on the work of many projects and their authors:
- whitebox_next_gen by John Lindsay, whose
pure-Rust format libraries (
wbraster,wbvector,wbprojection) terrio began on. - GDAL, PROJ and PDAL, the reference terrio follows and tests against; its projections are ported from PROJ, its point cloud filters follow PDAL's (the cloth simulation filter of Zhang et al., 2016, is a port of the CSF code PDAL vendors).
- The EPSG Geodetic Parameter Dataset of IOGP and Esri's projection engine data, for the coordinate reference systems.
- rasterio, xarray and rioxarray, whose APIs the Python package follows and whose code parts of it are adapted from.
- The pure-Rust crates terrio reads and writes its formats with, among them
tiff,png,jpeg-decoder,openjp2,rusty_av1d,jxl-oxide,lerc-reader,flatgeobuf, Apache Arrow and Parquet,netcdf-reader,hdf5-reader,lazande57; and clap, rayon, serde, PyO3 and wasm-bindgen.
See the acknowledgements for the full list.
Disclaimer
terrio is primarily built with Claude Opus 5.5, an AI model by Anthropic, working under human direction and review. Its results are tested against GDAL, PROJ and PDAL, but check them for your own use, and please report anything that looks wrong.
License
MIT
terrio's EPSG table and datum names (crates/terrio/data/epsg.tsv.zst, datums.tsv.zst) are
derived from the EPSG Geodetic Parameter Dataset, copyright the International
Association of Oil & Gas Producers (IOGP), whose terms of use
permit their redistribution with this attribution; its ESRI table (esri.tsv.zst) from Esri's
projection engine data (Apache-2.0). The
tables were produced with PROJ and GDAL. The projection
formulas in crates/terrio/src/crs/ are ported from PROJ (MIT licence), and the cloth simulation
filter from CSF (Apache-2.0). NOTICE holds the notices of the code and data terrio
adapts, and LICENSE-THIRD-PARTY.md the licenses of the Rust crates
it is built with.