Python
Python bindings for terrio: read, write, convert and reproject geospatial rasters and vector datasets in pure Rust, without GDAL. Wheels need only NumPy.
pip install terrio
Rasters
import terrio
dem = terrio.open_raster("dem.tif")
dem.width, dem.height, dem.count, dem.dtype # dtype is a NumPy name: "float32", "uint8"...
dem.crs, dem.transform, dem.bounds, dem.nodata
elevation = dem.read(1) # numpy array (rows, cols) of the raster's own dtype
everything = dem.read() # (bands, rows, cols)
# GeoTIFFs and COGs, local or remote, can be read by window: only the tiles a window needs are
# decoded, and fetched with HTTP range requests.
cog = terrio.open_raster("https://example.com/cog.tif", lazy=True)
cog.overviews # [(width, height), ...] of the overviews, largest first
tile = cog.read(1, window=(1024, 1024, 512, 512)) # (col_off, row_off, width, height)
thumb = cog.read(overview=2)
out = terrio.Raster.from_array(elevation * 3.28084, dem.transform, crs=dem.crs, nodata=dem.nodata)
out.write("dem_feet.tif", compress="DEFLATE")
out.write("dem_feet_cog.tif", driver="COG")
Vector data
ds = terrio.open_vector("countries.gpkg") # or .shp, .geojson, .fgb, .parquet, .kml, .zip...
layer = ds.layers[0] # also ds["countries"]
layer.name, layer.crs, layer.geometry_type, layer.fields, len(layer), layer.bounds
collection = layer.to_geojson() # a GeoJSON FeatureCollection dict
wkb = layer.to_wkb() # one WKB geometry per feature
columns = layer.columns() # attribute values by field
gdf = layer.to_geopandas() # with geopandas installed
terrio.write_vector(layer.to_crs("EPSG:3857"), "countries_3857.fgb")
terrio.write_vector(collection, "countries.geojson") # GeoJSON dicts, GeoDataFrames...
Operations
The operations take the command-line options as keyword arguments. Inputs are paths or objects in memory; outputs are returned, and also written when a destination is given.
terrio.info("dem.tif", stats=True) # the same dict as `terrio info --json`
terrio.convert("countries.shp", "europe.gpkg", where="CONTINENT = 'Europe'", select=["NAME"])
terrio.convert("https://example.com/cog.tif", "window.tif", srcwin=(0, 0, 512, 512))
terrio.translate("dem.tif", "small.tif", outsize=("25%", "25%"), resampling="average")
terrio.warp("dem.tif", "dem_4326.tif", t_srs="EPSG:4326", resampling="bilinear")
terrio.mosaic(["n40w106.tif", "n40w107.tif"], "mosaic.tif")
terrio.rasterize("counties.gpkg", "pop.tif", attribute="POPULATION", tr=(0.01, 0.01), ot="Int32")
polygons = terrio.polygonize("landcover.tif", connectedness=8)
xs, ys = terrio.transform_points([699960], [3900000], "EPSG:32610", "EPSG:4326")
data = open("dem.tif", "rb").read()
raster = terrio.open_bytes(data, "dem.tif") # from bytes; to bytes with raster.to_bytes("x.tif")
Errors raise terrio.TerrioError subclasses, which also derive from the matching built-in
exceptions: NotFoundError is a FileNotFoundError, TerrioIOError an OSError, and
InvalidArgumentError, CRSError, UnsupportedError and InvalidDataError are ValueErrors.
Building from source
cd python
uv venv && uv pip install maturin numpy pytest
uv run maturin develop --release
uv run pytest