The Pure Rust GDAL alternative just finished the most thorough defect hunt of its life — and came out the other side with real codecs where stubs used to be.
Today we released OxiGDAL 0.1.7 — a production-hardening release that fixes 233 verified defects across 69 crates, replaces half a dozen silent stub implementations with real, spec-conformant codecs, and ships three new hosted WebAssembly demos on top of the existing GeoLab viewer.
No C. No C++. No Fortran. No PROJ/GEOS, no libsqlite3, no ring — the C-free default build that 0.1.6 established doesn’t move an inch in 0.1.7. What changes is what’s underneath that promise: a systematic, multi-lane defect sweep found and fixed 233 real bugs — silent no-ops, an unread security check, a fake placeholder blob — the kind of thing that doesn’t show up until someone is depending on the answer being correct. OxiGDAL still compiles to a single static binary (or a sub-1MB WASM bundle) and runs everywhere Rust runs: Linux, macOS, Windows, WASM, iOS, Android, and bare-metal no_std.
Why OxiGDAL 0.1.7 is a game changer
GDAL’s problems are well known to anyone who has fought a configure script at 2am:
- A C/C++ toolchain plus PROJ, GEOS, and libcurl just to get off the ground
- Cross-compilation to WASM, iOS, Android, or embedded targets ranging from painful to unsupported
- Thread-unsafe APIs and C error codes instead of a typed
Result - A 50MB+ monolithic binary even when you only need a fraction of its surface
OxiGDAL 0.1.7 ends all of that — and adds a second, quieter promise on top: the code that ships does what its name says. A production-hardening campaign audited the workspace end to end this cycle and fixed 233 verified defects, several of which were silent-corruption or silent-bypass bugs that had already shipped in earlier releases without anyone noticing:
- The GeoTIFF float predictor was silently corrupting data. TIFF
Predictor=3decode and encode passed float32/float64 tile data straight through unmodified while claiming to apply the horizontal float predictor — every round-trip of a predictor-encoded float COG came out wrong. Both directions are now genuinely implemented. - JPEG2000 gets a real Tier-2 decoder. The MQ arithmetic decoder’s
INITDECprocedure is now ITU-T T.800 Annex C-conformant, and a newtier2module drives code-block decoding from the actual per-(resolution, subband, code-block) precinct geometry and COD progression order — replacing a naive even-division byte split that didn’t reflect real JPEG2000 packet structure. - FlatGeobuf is finally really FlatGeobuf. The reader and writer previously used an ad-hoc custom binary layout that only round-tripped against its own reader. 0.1.7 writes and parses the genuine size-prefixed FlatBuffers wire format via
flatbuffers::FlatBufferBuilder, independently verified by a new test that walks the on-disk bytes — files now interoperate with GDAL and other FlatGeobuf tooling. - An RBAC privilege-widening bug is closed.
resource_patternmatching was parsed and stored — but never actually consulted by the authorization check, so any pattern-scoped permission silently matched every resource. It’s consulted now. - HDF5 and NetCDF run on real Pure-Rust engines, not a JSON sidecar.
oxigdal-drivers/hdf5andoxigdal-netcdfread and write genuine files viaoxih5andoxinetcdf, and the ScaleOffset/N-Bit HDF5 filters now match libhdf5’s actual on-diskcd_valueslayout. DatasetWriter::finalize()stopped lying. On unsupported paths it used to emit a fakeOXIG-prefixed placeholder blob; now it writes a real format or returns a typed error.
Technical Deep Dive: what 0.1.7 rebuilt
-
Format-driver correctness (
oxigdal-geotiff,oxigdal-jpeg2000,oxigdal-flatgeobuf,oxigdal-drivers/hdf5,oxigdal-netcdf,oxigdal-drivers/gml,oxigdal-drivers-advanced) Beyond the headline fixes above: GeoTIFF’s LERC2 decoder now implements the real Esri/GDAL bit-stuffed block format (header parsing, RLE validity mask,BitStuffer2variable-bit-width unpacking, exact dequantization) — LERC encode stays an honest typed error rather than a fabricated blob. GML now parsessrsDimensionso 3D geometries stop getting silently flattened to 2D, and VRT’sFirstValidpixel function is fixed for multi-byte samples (u16/f32/f64) whileBandMathrecognizesB10and higher (previously dropped pastB9). -
Security & authorization hardening (
oxigdal-security,oxigdal-gateway) Beyond the RBAC fix: TOTP verification moved to constant-time comparison with a ±1 time-step (30s) clock-skew tolerance per RFC 6238 §5.2, and backup-code/SMS-challenge comparisons are constant-time too.oxigdal-security’s dependencies now split intoenterprise/tls/attestationfeatures (default enables all three), and the new attestation module — a domain-separated blake3 hash chain, a Merkle root with per-entry inclusion proofs, and an Ed25519 session seal — compiles forwasm32under--no-default-features --features attestation. -
Cloud & service real-wiring (
oxigdal-cloud,oxigdal-cloud-enhanced,oxigdal-services,oxigdal-query,oxigdal-server) Azure IMDS managed-identity tokens and GCP metadata/IAM-impersonation tokens are real now, not placeholders; a multicloudbuild_backend()factory (S3/GCS/AzureBlob/Http) ships with a backend cache; WFS-T transactions and WCS coverage read/write are fully implemented against real GeoTIFF I/O;GROUP BYactually executes in the SQL query engine; andserver.tomlis actually loaded viaOXIGDAL_CONFIGin Docker/Kubernetes deployments instead of being silently discarded. -
Browser-native demos + GeoParquet pushdown (
oxigdal-wasm,oxigdal-wasm-geoparquet,oxigdal-geoparquet) Newplan_pushdown()/execute_pushdown()APIs compute row-group and column-chunk byte ranges from Parquet footer metadata alone — zero I/O — and now correctly detect GeoParquet 1.1covering.bboxpaths at real scale (the 5.9 GB, 9,533-row-group VIDA dataset prunes correctly). A new crate,oxigdal-wasm-geoparquet, brings a browser range-request client with SQL-fragment predicate pushdown. Three new hosted demos — GeoSentinel, GeoVault, GeoParquet Live — join the rebranded GeoLab, all sharing the same WASM package.
Getting Started
cargo add oxigdal
GeoTIFF, GeoJSON, and Shapefile ship by default — add --features full for all 17 format drivers.
use oxigdal::Dataset;
fn main() -> oxigdal::Result<()> {
let dataset = Dataset::open("world.tif")?;
println!("Format : {}", dataset.format());
println!("Size : {}x{}", dataset.width(), dataset.height());
println!("CRS : {}", dataset.crs().unwrap_or("unknown"));
Ok(())
}
This is the Quick Start straight from the README — and as of 0.1.7, it actually compiles as written (crs() returns an Option, a real doc-accuracy fix landed this release).
What’s New in 0.1.7
- 233 verified defects fixed across 69 crates in a parallel production-hardening sweep — correctness, unwrap-elimination, clippy, and doc/README accuracy.
- GeoTIFF float predictor (
Predictor=3) genuinely implemented for both decode and encode — was a silent no-op corrupting float COG round-trips. - JPEG2000: MQ decoder
INITDECnow ITU-T T.800 Annex C-conformant; a real Tier-2 packet-header/precinct decoder replaces a naive byte-split; unsupported progression orders or multi-layer streams now return a typed error instead of mis-decoding. - FlatGeobuf reader/writer rewritten to the genuine size-prefixed FlatBuffers wire format (was a custom ad-hoc layout) — interoperable with GDAL and other FlatGeobuf tooling.
- GeoTIFF LERC2 decoder — the real Esri/GDAL bit-stuffed block format, header through dequantization; encode remains an honest typed “unimplemented,” not a fabricated blob.
- HDF5 / NetCDF re-backed by the real
oxih5/oxinetcdfengines; ScaleOffset/N-Bit filters now match libhdf5’s actual on-disk layout. - Security: RBAC
resource_patternbypass closed; TOTP/backup-code/SMS comparisons now constant-time with RFC 6238 clock-skew tolerance; newattestationmodule (blake3 chain → Merkle root → Ed25519 seal, wasm32-ready). - Cloud: real Azure IMDS managed-identity and GCP metadata/IAM-impersonation tokens; multicloud
build_backend()factory (S3/GCS/AzureBlob/Http) with a backend cache. - Services: WFS-T Memory/File transactions fully implemented; WCS coverages do real GeoTIFF read/write;
GROUP BYimplemented in the SQL executor;server.tomlactually loaded viaOXIGDAL_CONFIG. - GeoParquet: new
plan_pushdown()/execute_pushdown()zero-I/O pruning API; GeoParquet 1.1covering.bboxdetection verified at VIDA scale (5.9 GB, 9,533 row groups);AttributeFilter::Cmpwith Int64/Float64 coercion. - New crate
oxigdal-wasm-geoparquet— a browser GeoParquet range-request client with SQL-fragment predicate pushdown, published as@cooljapan/oxigdal-geoparquet. - Three new hosted demos — GeoSentinel (Sentinel-2 change detection), GeoVault (attested clean-room workstation), GeoParquet Live (5.9 GB queried with no database) — alongside the rebranded GeoLab.
- ML: a pure-Rust ONNX protobuf export encoder round-trip validated against
oxionnx;OnnxModel::infer_multibandfor real multi-channel NCHW tensor inference (previously single-band only). - GPU: native WGSL subgroup builtins with a workgroup-shared-memory emulation fallback; new Metal filter/reduction/nearest-neighbor shader generators.
- Hardening: raster-algebra expression parsers now cap nesting depth (
MAX_EXPRESSION_DEPTH = 64) instead of stack-overflowing on adversarial input;oxigdal-corecompiles under--no-default-features --features alloc(no_std + alloc, no std). - Docs.rs metadata added to all 64 remaining publishable crates; new
CONTRIBUTING.md/CODE_OF_CONDUCT.md.
Tips
- Plan before you fetch.
GeoParquetReadernow supports zero-I/O pushdown planning — build the filter, then letread_pushdown()compute exactly which row groups and column-chunk byte ranges survive before any data is read:use oxigdal_geoparquet::{AttributeFilter, CmpOp, GeoParquetReader, ScalarValue}; let reader = GeoParquetReader::open("buildings.parquet")? .with_bbox_filter((135.0, 34.0, 137.0, 36.0)) .with_attribute_filter(AttributeFilter::Cmp { col: "floors".to_string(), op: CmpOp::Gt, value: ScalarValue::Int64(10), }); let batches = reader.read_pushdown()?; // row-group + column-chunk pruning already happened - Tamper-evident logs without a server. The new
attestationfeature builds aSessionLog, seals it withSessionSigner::seal(...), and lets anyone re-derive the chain, Merkle root, and signature straight from the resulting JSON viaverify_attestation(json)— no private key or network round-trip needed to check it.--no-default-features --features attestationpulls in onlyblake3+ed25519-dalek, so it’s viable onwasm32. - Move off the
reqwestfeature name onoxigdal-stac. It’s now a backwards-compatible alias for the real gate,async— new code should requestfeatures = ["async"]directly. - Use
infer_multibandfor real multi-channel models. If your ONNX model expects more than one input channel,OnnxModel::infer_multibandnow builds a genuine[1, C, H, W]tensor instead of making you loop the single-bandinferper channel. - Regenerate old FlatGeobuf files for external interop. Files written before 0.1.7 used an ad-hoc custom layout that only ever round-tripped against oxigdal’s own reader — never real, standards-compliant FlatBuffers. If you need
.fgboutput that opens in GDAL,ogr2ogr, or other FlatGeobuf tooling, regenerate it with 0.1.7’s writer. - Catch
AlgorithmError::NestingTooDeep, don’t crash. If you evaluate raster-algebra expressions from untrusted input, the parser now enforces a depth cap instead of a stack-overflow abort — handle the typed error rather than assuming deeply nested input just works.
This is the foundation
0.1.7 leans on more of the COOLJAPAN stack than any OxiGDAL release before it, and tightens several of those bonds directly this cycle: CRS transforms run on OxiProj, HDF5 and NetCDF read/write through oxih5 and oxinetcdf (both bumped to 0.2.0 this cycle and verified source-compatible with zero driver-side changes), SQLite via oxisql-sqlite-compat (Limbo), TLS via OxiTLS, compression across the format drivers via the OxiArc family (oxiarc-zstd, -lz4, -deflate, -lzw, -bzip2, -brotli, -snappy, -archive), ML tensor math via SciRS2-Core (plus scirs2-neural, -autograd, -optimize), model export and inference validated against OxiONNX, and model-weight serialization on OxiCode instead of bincode. Every one of those is itself Pure Rust — which is how a 76-crate, ~747K-SLoC workspace gets to a C-free default build with no hidden native dependency anywhere in the tree.
Repository: https://github.com/cool-japan/oxigdal
One honest footnote: this is the last release under the OxiGDAL name. Development continues as OxiGeo starting with v0.2.0 — nothing above changes because of that; the 233 fixes, the three demos, and the 76 crates are exactly as real either way.
Star the repo if you want a geospatial stack that treats “it compiles” and “it’s correct” as two separate bars — and clears both. The era of wondering whether your GDAL-adjacent dependency tree is quietly doing the wrong thing is over.
— KitaSan at COOLJAPAN OÜ July 20, 2026