COOLJAPAN
← All posts

OxiProj 0.1.0 Released — A Near-Complete Pure-Rust Port of PROJ 9.8.0

OxiProj 0.1.0 debuts: a 100% Pure-Rust replacement for proj-sys / PROJ. A near-complete port of PROJ 9.8.0 with ~197 projections, full Karney geodesics, ISO-19111 CRS, the EPSG proj.db via oxisql-sqlite-compat, and 1345 passing tests — no C, no FFI.

release oxiproj proj gis cartography geospatial pure-rust crs map-projections epsg

The last big -sys liability in COOLJAPAN geospatial just got a Pure-Rust answer.

Today we released OxiProj 0.1.0 — a near-complete, 100% Pure-Rust port of PROJ 9.8.0 that reimplements coordinate reference systems, datum transformations, and map projections with no C, no FFI, and no native dependencies.

No C. No C++. No Fortran. No proj-sys, no libproj, no PROJ toolchain dragged into your build. OxiProj is not a binding — it is a faithful reimplementation of PROJ 9.8.0 in Rust: the same proj-string semantics, the same projection math, the same EPSG codes. The default build is 100% Pure Rust with no database and no FFI whatsoever. The optional EPSG proj.db is served by the Pure-Rust oxisql-sqlite-compat engine — no native SQLite, no C library. It compiles to a single static binary (and to WASM), and it runs everywhere a Rust target does.

Why OxiProj 0.1.0 — and why now

The COOLJAPAN ecosystem is committed to being C/C++/Fortran-free. By mid-2026, proj-sys — the bindings to the C PROJ library — was the single largest remaining FFI liability in the entire stack. Every geospatial CI run had to drag libproj and PROJ’s full C toolchain along just to reproject a coordinate. That pain landed hardest on OxiGDAL, our Pure-Rust GDAL effort, where proj-sys was the last thing standing between it and a fully sovereign build.

OxiProj exists to purge that dependency. And at 0.1.0 it already arrives close to complete:

This is a 0.1.0, and we say so honestly — but it is an ambitious one.

Technical Deep Dive: how the port is laid out

OxiProj is split into ten crates, each mirroring a layer of PROJ’s responsibilities.

The numerical and geodesic core. oxiproj-core holds the coordinate types, ProjError with the full PROJ_ERR_* taxonomy, the Ellipsoid type with derived parameters, the ellps/units/prime-meridian/datum tables, DMS parsing, the PROJ numeric helpers (pj_mlfn, pj_msfn, pj_tsfn, pj_phi2, pj_gauss, proj_mdist), and the Operation trait. On top of that, oxiproj-geodesic is a faithful port of the Karney geodesic algorithms from PROJ 9.8.0 / GeographicLib — direct, inverse, and area, with GeodesicLine and PolygonArea.

The engine and the projection catalog. oxiproj-engine is the proj-string tokenizer and parser, ellipsoid setup, forward/inverse prepare-and-finalize, the operation registry, and +proj=pipeline with +step and per-step +inv. oxiproj-projections carries the whole ~197-projection PROJ 9.8.0 catalog. The 0.1.0 release completed it from a 21-projection core to the full set — the Eckert/Wagner/Putnins/McBryde pseudocylindricals, van der Grinten, the Adams/Guyou/Peirce elliptic-integral conformals, Krovak, the HEALPix/rHEALPix/QSC/S2/ISEA polyhedral family, interrupted Goode and Mollweide, and Space Oblique Mercator.

Transformations and grids. oxiproj-transformations covers the conversions (noop, axisswap, unitconvert, cart, geocent, geoc, topocentric, set) and the datum transforms: Helmert 3/4/7-parameter (including position-vector and coordinate-frame conventions), time-dependent Helmert, Molodensky-Badekas, Molodensky, affine, geogoffset, vertoffset, and the grid-based operations (hgridshift, vgridshift, xyzgridshift, gridshift, tinshift, deformation). The tenth crate, oxiproj-grids, supplies the grid readers — NTv2 .gsb, GTX, GeoTIFF via hand-rolled TIFF-tag parsing with OxiARC deflate, plus TIN/tinshift — with bilinear interpolation and an LRU grid cache. It is Pure-Rust by default; CDN grid fetch is opt-in behind the network feature.

CRS and the operation factory. oxiproj-crs is the ISO-19111 CRS model — Geographic, Geodetic, Projected, Vertical, Compound, Temporal (TIMECRS), and Engineering (ENGINEERINGCRS) — with WKT1 (GDAL), WKT2:2019, the ESRI dialect, and PROJJSON I/O behind the projjson feature. Its CoordinateOperationFactory does real pathfinding: direct DB lookup, then a datum-hub pivot, then candidate ranking, then a ballpark fallback, with AreaOfUse enforcement and CRS-native axis order. Finally, oxiproj-db bundles the full EPSG proj.db, read through the Pure-Rust oxisql-sqlite-compat engine behind the opt-in epsg feature — replacing the curated ~130-code subset with the complete authority database. The oxiproj facade and oxiproj-cli round out the ten.

Getting Started

Add it to your project — the default build is Pure Rust, with no DB and no FFI:

cargo add oxiproj

Want EPSG codes? Turn on the opt-in epsg feature, which pulls in the full proj.db via oxisql-sqlite-compat:

cargo add oxiproj --features epsg

Then reproject a coordinate. Note the GIS lon, lat (degrees) convention by default — and that there is no Transformer::from_proj: you build a Crs first, then construct a Transformer from a source and target.

use oxiproj::{Crs, Transformer, Coordinate};

fn main() -> Result<(), oxiproj::ProjError> {
    // WGS84 geographic (lon, lat degrees) -> Web Mercator (meters)
    let wgs84 = Crs::wgs84()?;
    let webmerc = Crs::web_mercator()?;
    let t = Transformer::new(wgs84, webmerc)?;

    let input = Coordinate { x: 9.0, y: 48.0 };   // x = lon, y = lat
    let out = t.transform(&input)?;
    println!("Web Mercator: x = {}, y = {}", out.x, out.y);

    // Build a CRS from a proj-string, then transform into it
    let utm32 = Crs::from_proj("+proj=utm +zone=32 +datum=WGS84")?;
    let to_utm = Transformer::new(Crs::wgs84()?, utm32)?;
    let projected = to_utm.transform(&input)?;
    println!("UTM 32N: x = {}, y = {}", projected.x, projected.y);
    Ok(())
}

Prefer the command line? The facade CLI ships a transform subcommand:

oxiproj transform "+proj=utm +zone=32 +datum=WGS84" 9.0 48.0

What’s inside

Tips

This is the foundation

OxiProj fits into COOLJAPAN’s broader push to purge every -sys crate from the ecosystem. It already leans on real siblings: OxiARC (oxiarc-deflate) compresses its grid data, oxisql-sqlite-compat serves the EPSG database without native SQLite, and oxihttp powers CDN grid fetch behind the network feature.

The north star, though, is OxiGDAL. OxiProj’s whole reason for being is to let OxiGDAL drop proj-sys and finally build C-free. That cutover — swapping OxiGDAL onto OxiProj and removing proj-sys — remains as future work, blocked pending sign-off. We are calling it out honestly: it’s the headline goal still ahead of us, not something already done.

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

Star the repo if you want a geospatial stack that builds without a C toolchain. Pure Rust cartography is here — no libproj, no FFI, no C toolchain.

KitaSan at COOLJAPAN OÜ June 19, 2026

↑ Back to all posts