COOLJAPAN
← All posts

OxiGeo 0.2.3 Released — Warped VRTs Finally Parse, and Vector Layers Get a Real `Dataset::layers()` API

OxiGeo 0.2.3 fixes GitHub issue #15 — every gdalwarp -of VRT product was rejected at parse time — with a real backward warp engine in oxigeo-vrt, and issue #16 — Dataset::open on a GeoPackage always reported 0 layers — with a new Dataset::layers()/Layer::features() vector API for GeoPackage, Shapefile, and GeoJSON.

release oxigeo gdal geospatial pure-rust vrt gis

A VRT driver that understands mosaics and pixel functions but not warps only understands two-thirds of what GDAL actually writes.

Today we released OxiGeo 0.2.3 — built around two GitHub issues from real users. Issue #15 reported that oxigeo-vrt rejected every gdalwarp -of VRT product — a Warped VRT’s <GDALWarpOptions> block — with “Band must have at least one source or a pixel function”: the driver had no concept of a warp at all. Issue #16 reported that vector-layer support was incomplete: Dataset::open on a GeoPackage reported layer_count() == 0, with no public API to read a layer’s features regardless of format. Both are now implemented for real — 1,635 new lines in oxigeo-vrt and 1,405 new lines in the oxigeo facade.

No C. No C++. No Fortran. OxiGeo 0.2.3 still compiles to a single static binary (or WASM) and runs everywhere Rust runs — and it ships a real reprojection engine without picking up a single new native dependency to get there.

Why 0.2.3 is a game changer

A format driver that silently understands only part of the format it claims to support fails in the worst way — at parse time, on real-world files:

OxiGeo 0.2.3 ends all of that:

Technical Deep Dive: what issues #15 and #16 actually touched

  1. The warp engine (oxigeo-vrt::warp). WarpOptions is the parsed <GDALWarpOptions> block; WarpResampleAlg::is_kernel_exact() reports which resample algorithms the engine runs exactly versus approximates — stated honestly rather than silently: NearestNeighbour and Bilinear are exact today, while Cubic/CubicSpline/Lanczos/Average/Mode parse and select correctly but currently resample bilinearly.
  2. A new VrtError::EmptyWindow variant. Distinguishes “no source covers this window” — legitimate on a warp over a sparse mosaic, mirroring GDAL’s ERROR_OUT_IF_EMPTY_SOURCE_WINDOW=FALSE behavior — from a genuine structural error, so a routine mosaic gap can no longer mask a real bug.
  3. A quick-xml 0.41 entity-reference fix. quick-xml reports &quot;/&amp;/&#34; as their own Event::GeneralRef, separate from surrounding Event::Text; those events fell through the parser’s catch-all arm and vanished, so a <SRS> block written by this crate’s own VrtXmlWriter read back with every " silently missing.
  4. gpkg_schema, shared across two read paths. The same CREATE TABLE column/constraint parser now backs both the new layers() reader and the existing streaming GeoPackage path — including is_table_constraint, which stops CONSTRAINT pk_geom_cols PRIMARY KEY (...)-style body items from being parsed as bogus extra columns.
  5. oxigeo-vrt gained a dependency on oxigeo-proj to perform the reprojection — still Pure Rust, since oxigeo-proj’s default feature set excludes the oxiproj-db/tokio EPSG-database path, so this doesn’t pull SQLite into a default oxigeo-vrt build.

Getting Started

[dependencies]
oxigeo = "0.2"  # GeoTIFF + GeoJSON + Shapefile by default
use oxigeo::Dataset;

fn main() -> oxigeo::Result<()> {
    // Works for plain, mosaic, AND warped VRTs now — including whatever
    // `gdalwarp -of VRT` wrote, previously rejected at parse time.
    let dataset = Dataset::open("warped.vrt")?;
    println!("{}x{}, {} bands", dataset.width(), dataset.height(), dataset.band_count());
    let band0: Vec<u8> = dataset.read_band(0)?;

    // GeoPackage needs the (non-default) `gpkg` feature; .shp/.geojson are on by default.
    let cities = Dataset::open("cities.gpkg")?;
    let layer = cities.layer(0)?;                 // or .layer_by_name("cities")
    println!("{} ({:?}), {:?} features", layer.name(), layer.geometry_type(), layer.feature_count());

    for feature in layer.features()? {
        // feature.geometry: Option<oxigeo::Geometry>, feature.properties: HashMap<String, oxigeo::FieldValue>
        println!("{:?} — {:?}", feature.geometry, feature.properties);
    }
    Ok(())
}

What’s New in 0.2.3

Tips

This is the foundation

OxiGeo 0.2.3 leans on the same Pure Rust COOLJAPAN stack as every release before it — and this release leans on it a little more directly: the new warp engine’s reprojection runs through OxiProj, the same CRS layer that powers oxigeo-proj’s standalone transforms. HDF5/NetCDF read-write continues through oxih5 and oxinetcdf, SQLite via oxisql-sqlite-compat (Limbo) — now doing double duty for both the streaming and the new layers() GeoPackage paths — TLS via OxiTLS, compression across every format driver via the OxiArc family, ML tensor math via SciRS2-Core (bumped to 0.6.5 this release), and model export validated against OxiONNX. Every one of those is itself Pure Rust — which is how a 75-crate, ~797K-SLoC workspace ships a real reprojection engine without picking up a single new native dependency.

Repository: https://github.com/cool-japan/oxigeo

Star the repo if you’d rather your VRT driver understood the file GDAL actually wrote than reject it at parse time. Two real user-filed issues, two real fixes — a warp engine and a vector-layer API, both grounded in files that were failing before today.

The era of “the VRT driver almost works” is over. Pure Rust geospatial is here — fast, safe, and sovereign.

KitaSan at COOLJAPAN OÜ
August 5, 2026

↑ Back to all posts