Releases: cool-japan/oxigeo
Release list
OxiGeo 0.2.4 Release
[0.2.4] - 2026-08-18
Added
oxigeo-proj: added the unambiguous type aliasesSphericalTransverseMercator(=TransverseMercator) andEllipsoidalTransverseMercator(=GaussKruger), re-exported at the crate root, so call sites can state which Earth model they mean —TransverseMercatoris sphere-based and is wrong for UTM/national grids by ~24.9 km of northing at 48° N, which its docs now warn about prominently; a new regression test pins the two apart at a real UTM 33N reference point.oxigeo-proj: re-exported the ellipsoidal Transverse Mercator kernelprojections::tmerc_forward/projections::tmerc_inversefromprojections(previously reachable only asprojections::cylindrical::tmerc_*).oxigeo-proj:transformnow re-exportsSphericalTransverseMercatorandEllipsoidalTransverseMercatoralongsideCassineSoldner/GaussKruger/TransverseMercator, souse oxigeo_proj::transform::*surfaces the two aliases instead of forcing the longertransform::cylindrical::path. Samestdgate as the existing re-exports; a regression test now imports them through the glob and checks they denote the same types as the crate-root re-exports.oxigeo-geoparquet:GeoParquetReader::from_bytes(impl Into<bytes::Bytes>)reads a GeoParquet image held entirely in memory. The reader now keeps an internalFile/Bytessource that implementsChunkReader, so every read path —read_geometries,read_row_group,read_all,read_pushdown— behaves identically for on-disk and in-memory inputs, with no change toGeoParquetReader's public shape.oxigeo-geoparquet:GeoParquetReader::read_geometries_optional(row_group)andGeoParquetBatchReader::extract_geometries_optional(batch)returnVec<Option<Geometry>>with exactly one entry per row, so geometries stay index-aligned with their property rows;GeoParquetBatchReader::geometry_encoding()exposes the geometry column's declared encoding.oxigeo-geotiff:tiff::is_mask_ifd(&Ifd, ByteOrderType)classifies a directory as a GDAL internal (transparency) mask, with the pure coretiff::is_mask_markers(new_subfile_type, photometric)and the marker constantstiff::SUBFILE_TYPE_TRANSPARENCY_MASK/tiff::PHOTOMETRIC_TRANSPARENCY_MASK.oxigeo-geotiff:CogReader::ifd_count(),CogReader::level_ifd(level)andCogReader::level_ifd_index(level)expose the level → IFD mapping and the raw chain length, so a consumer that wants the mask IFDs — or wants to know how many non-level IFDs a file carries — can still reach them while the level API stays mask-free.oxigeo-geotiff:CogReader::tile_pixel_size(level, tile_y)returns the decoded pixel dimensions of the blockread_tileproduces at that level — the level's ownTileWidth/TileLength, orImageWidth × RowsPerStripnarrowed for the short final strip — so a caller can size an image buffer that cannot disagree with the bytes it gets.oxigeo-gpkg:GeoPackage::scan_table_by_name_typed(table)scans a table likescan_table_by_namebut applies SQLite's REAL type affinity to the result: SQLite stores a lossless40.0in aREAL/DOUBLE/FLOAT-declared column as the integer40, so an untyped scan surfaces it as anInteger— the typed variant restores every such value to the equivalentFloat(viarestore_real_affinity, driven by the declared column types), so40and40.0read back identically, matching what every affinity-aware SQLite consumer sees.scan_table_by_nameitself is unchanged and still returns raw storage classes.
Changed
- Renamed the workspace
quick-xmldependency (Cargo.toml) to theoxixml-quickxml-compatpackage (drop-in quick-xml 0.41 compatible shim), keeping the local dependency namequick-xmlso every consuming crate (oxigeo-drivers-advanced, oxigeo-vrt, oxigeo-services, oxigeo-server, oxigeo-metadata, oxigeo-qc) required no source changes. deny.toml: added aquick-xmlentry to[bans].deny, scoped withwrappers = ["inferno"]for the one remaining transitive path (inferno -> pprof -> oxigeo-algorithms's dev-onlypprofdependency); the direct-consumer graph is clear (cargo tree -i quick-xml -e normal --workspaceis empty).oxigeo-gpkg: gated GeoJSON conversion (vector::geojson_convert, and itsoxigeo-geojson-stream/serde_jsondependencies) behind a newgeojson-convertfeature, kept indefaultso no existing build breaks;cargo build --no-default-features(e.g. for wasm) no longer pulls in theregexfamily viaoxigeo-geojson-stream. Consumers that already buildoxigeo-gpkgwithdefault-features = falsewill need to addfeatures = ["geojson-convert"]to keep usingvector::geojson_convert.oxigeo-proj: theoxiprojdependency is nowoptionaland pulled in by thestdfeature instead of being unconditional. Every OxiProj call site already lived in astd-gated module (transform,pipeline,projections, …), so a--no-default-features(no_std + alloc) build was compiling OxiProj purely as dead weight;cargo tree -p oxigeo-proj --no-default-features -e normalnow lists onlybyteorder,serdeandthiserror.default = ["std"]is unchanged, so the default public surface is byte-identical and the 13 in-workspace dependents (all of which use default features or ask forstdexplicitly) need no change. Migration: two trait impls —impl From<oxiproj::TransformError> for Errorandimpl From<oxiproj::ProjError> for Error— are now#[cfg(feature = "std")]and therefore absent from--no-default-featuresbuilds; they could not have been used there anyway, since theoxiprojtypes they convert from were not linked. NoErrorvariant changed: all of them carryString, not OxiProj types.--no-default-features --features proj-dbremains unsupported (it was already failing to compile before this change, for unrelatedallocprelude reasons inepsg::proj_db) — superseded later in this same release:proj-dbnow impliesstdand compiles, see Fixed below.- Dependency bumps:
oxiproj0.1.5 — the OxiProj authority-path correctness release, which fixes upstream the divergent EPSG authority definitions documented in theproj-dbfeature-invariance entry under Fixed (unit-converted ellipsoid axes, method-aware+lat_tsmapping, LCC 1SP, WGS 84-hub datum composition, prime-meridian datum chains, Molodensky-Badekas operations, PROJ's ballpark/fallback selection policy, and grid direction underPROJ_DATA) — plus routine COOLJAPAN ecosystem bumps (oxiarc,oxicode,oxih5,oxionnx,oxisql,oxistore,oxitls; thequick-xml→oxixml-quickxml-compatmigration has its own entry above). oxigeo-gpkg:SqliteHeadergained the public fieldreserved_bytes: u8(byte 20 of the SQLite database header — bytes reserved at the end of every page) and ausable_size()helper; the issue #17 overflow-page fix (see Fixed) computes local-payload thresholds from the usable page size, not the raw page size. Compatibility note: constructingSqliteHeaderwith a struct literal outside the crate now requires the extra field; code that obtains headers throughSqliteReaderis unaffected.oxigeo-wasm:WasmCogViewer,AdvancedCogViewerandBatchTileLoaderhold their cached parsed reader (see the reader-reuse fix under Fixed) inRc/RefCelland therefore no longer implementSend/Sync. Onwasm32-unknown-unknown— the target these#[wasm_bindgen]types exist for — this is inert (single-threaded, driven from JS); only a non-wasm caller holding one behind aSend/Syncbound would notice, and none exists in the workspace.
Fixed
oxigeo-geoparquet:GeoParquetBatchReader::extract_geometriesnow dispatches on the geometry column's declared encoding instead of downcasting toBinaryArrayunconditionally — a GeoArrow-native file read throughread_all()/next_batch()previously failed with atype_mismatcherror rather than decoding.oxigeo-geoparquet: null geometries no longer silently desynchronise geometries from their property rows — the newread_geometries_optional/extract_geometries_optionalvariants keep each null as aNoneat its original index (the existing null-dropping methods are unchanged).oxigeo-wasm: GDAL internal-mask IFDs (NewSubfileTypebit 2, orPhotometricInterpretation == 4) are no longer counted as overview levels by the browser COG reader — they share the IFD chain with the overviews, sooverviewCountwas inflated and every level index past the first mask was shifted onto the wrong resolution. The chain is still walked through masks, so overviews stored after one are found.oxigeo-wasm:WasmCogViewer.readTile(level, x, y)now honours itslevelargument on the URL path; it previously called a level-0 shortcut, so every overview request silently re-read full-resolution tiles.oxigeo-wasm:WasmCogViewerandAdvancedCogViewerparse the COG once and reuse the reader across tile reads instead of re-opening the file (HEAD request plus a range request per IFD) on every tile — forAdvancedCogViewerthat happened on every tile-cache miss. The cached reader is keyed by URL, so re-opening a different file never serves stale tiles, and a failed open is retried on the next call.oxigeo-wasm: the URL-backed COG path now normalisesModelPixelScaleTag(33550) Y to its magnitude, soWasmCogViewer.pixelScaleY(), thepixelScaleYkey of the metadata JSON, and the Rustpixel_scale_yfield ofCogMetadata/IfdMetadataare never negative. The GeoTIFF spec defines the tag as strictly positive and conforming writers (GDAL included) store it that way, but a few nonconforming writers bake the north-up sign into it; the URL path previously passed that negative value straight through while theopenBytespath already applied.abs(), so the same raster reported opposite signs depending on how it was loaded. Neither pa...
OxiGeo 0.2.3 Release
[0.2.3] - 2026-08-05
Issues #15 and #16. GitHub 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 understood mosaics and pixel-function VRTs but
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, and there was no public API to read
a layer's features regardless of format. Both are now implemented for real —
4 new files in oxigeo-vrt (1,635 lines: warp.rs, warped.rs, srs.rs,
source_dataset.rs) and 2 new files in oxigeo (1,405 lines: layer.rs,
gpkg_schema.rs) — alongside issue #14
("how do I read a GeoTIFF into ndarray::Array2"), which needed no code
change: the readers it asked for (read_band_into, read_window_into,
read_interleaved(_into), read_window_interleaved(_into)) already shipped
in 0.2.2.
Added
Warped VRT support (oxigeo-vrt, #15)
- New
warpmodule:WarpOptions(the parsed<GDALWarpOptions>block),
WarpResampleAlg—is_kernel_exact()reports which resample algorithms the
engine implements exactly rather than approximates, see the known-limitation
note under Fixed below —WarpKernel,WarpBandMapping,InitDest,
ReprojectionTransformer,GenImgProjTransformer. - New
srsmodule:resolve_crs, a WKT/PROJ4/EPSG:nCRS-string resolver. - New
source_datasetmodule:SourceDataset, which dispatches a warp's
source to a GeoTIFF leaf reader or recurses into a nested VRT
(MAX_VRT_NESTING = 16, so a VRT that references itself fails cleanly
instead of exhausting the stack). VrtDataset::with_warp_options/is_warped; a newVrtError::EmptyWindow
variant (VrtError::empty_window) that distinguishes "no source covers this
window" — legitimate on a warp over a sparse mosaic, GDAL's
ERROR_OUT_IF_EMPTY_SOURCE_WINDOW=FALSEbehavior — from a real structural
error, so a routine mosaic gap can't also mask genuine failures.oxigeo-vrtgained a new dependency onoxigeo-projto perform the
reprojection. Pure Rust:oxigeo-proj's default feature set excludes the
oxiproj-db/tokio EPSG-database path, so this does not pull SQLite into a
defaultoxigeo-vrtbuild.
Vector layers (oxigeo, #16)
Dataset::layers() -> Result<Vec<Layer>>,Dataset::layer(index),
Dataset::layer_by_name(name),Dataset::layer_names();Layer::features() -> Result<LayerFeatures>(eager). Newoxigeo::{Layer, LayerFeatures}, and
oxigeo::{Feature, FieldValue, Geometry}re-exported from
oxigeo-core::vectorso reading features needs no directoxigeo-core
dependency.- New
crates/oxigeo/src/layer.rs(thelayers()dispatch plus the
Shapefile/GeoJSON/GeoPackage readers) andcrates/oxigeo/src/gpkg_schema.rs
(aCREATE TABLEcolumn/constraint parser shared by the new layer reader and
the existing streaming GeoPackage path, so a schema fix lands in both at
once).
Changed
- Dependency bump:
scirs2-core0.6.4 → 0.6.5,oxicode0.2.4 → 0.2.5 —
routine latest-crates-on-crates.io maintenance.oxicode0.2.5 is a
hardening release (DoS/panic/overflow rejections added to its decode paths);
neither bump changes any OxiGeo-visible API or behavior.
Fixed
oxigeo-vrt (#15)
- Every Warped VRT was rejected at parse time. A
VRTWarpedRasterBand
legitimately carries no<SimpleSource>/<ComplexSource>/pixel function —
its pixels come entirely from the sibling<GDALWarpOptions>block — but
VrtDataset::validateapplied the same "Band must have at least one source
or a pixel function" rule regular VRTs need, rejecting every warped VRT GDAL
has ever written. The rule is now relaxed exactly when a validated
<GDALWarpOptions>block is present (VrtDataset::is_warped); a
VRTWarpedDatasetthat carries thesubClassmarker but no warp block is
still rejected, since it then has no source for any pixel. - Depth-aware
AUTHORITY/IDresolution in WKT CRS strings. The previous
scan returned the firstAUTHORITY[...]/ID[...]node found anywhere in
a WKT tree. In aGEOGCS, that is the node nested insideSPHEROID(e.g.
AUTHORITY["EPSG","7030"], the ellipsoid's own code), which precedes the
CRS's own root-level code (e.g.AUTHORITY["EPSG","4326"]) in the string. A
source WKT naming EPSG:4326 was silently resolved as EPSG:7030 — the wrong
CRS, and one close enough in practice to distort output rather than fail
loudly.srs::resolve_crsnow tracks bracket depth and reads only the
direct-childAUTHORITY/IDof the root node. relativeToVRTwas discarded on both read and write. Parsing a
<SourceFilename relativeToVRT="1">silently dropped the attribute (every
path was treated as absolute), and writing one never emitted it either — so
OxiGeo could not read back a VRT written by its ownoxigeo buildvrt
wherever that VRT used relative source paths. Both directions now round-trip
the attribute.- quick-xml 0.41 entity-reference events were dropped, corrupting escaped
text. quick-xml reports"/&/"as their own
Event::GeneralRef, separate from the surroundingEvent::Text; those
events fell through the XML parser's catch-all arm and vanished. A<SRS>
block written by this crate's ownVrtXmlWriter(which escapes the quotes
in a WKT tree) read back with every"missing, and any path containing&
silently lost it. VrtReader::read_window's band-to-index conversion was an uncheckedband - 1, an integer-underflow panic waiting for a caller that passed band0;
nowchecked_subwith a typedVrtError::band_out_of_rangeon failure.- The
oxigeofacade opened.vrtfiles with a zero-filled
DatasetInfo.Dataset::openrouted every VRT through the generic
fallback arm ofopen_raster:width()/height()/band_count()all read
back0andgeotransform()read backNone, for a file that states all
of them in its own header.raster_read'sread_band/read_window/
read_interleaved(and their_intoforms) were also hardwired to the
GeoTIFF path only.Dataset::opennow parses the VRT header for real
metadata via a newextract_vrt_info, and every raster read method
dispatches to the VRT reader — including through nested warps and mosaics —
whenever the opened dataset is a VRT. - Known limitation, stated rather than hidden:
WarpResampleAlg::is_kernel_exact()istrueonly forNearestNeighbour
andBilinear. Cubic, CubicSpline, Lanczos, Average, and Mode all parse
correctly and select their named kernel, but the warp engine currently
resamples every one of them bilinearly rather than with the kernel it
selected.
oxigeo GeoPackage / vector layers (#16)
Dataset::open("x.gpkg")always reported 0 layers. The facade's
open_vectorhad no GeoPackage arm at all, so every.gpkgfell through to
an emptyDatasetInfo::default().open_vectornow calls the new
extract_gpkg_infounder the (non-default)gpkgfeature.fidread backNULLon every GeoPackage feature. SQLite stores an
INTEGER PRIMARY KEYcolumn asNULLin the row's record payload and keeps
the real value only in the row's own 64-bitrowid; naively reading the
stored cell therefore always produced a nullfid.gpkg_schemanow
detects anINTEGER PRIMARY KEYcolumn at schema-parse time
(rowid_alias) and substitutes the row'srowidfor it whenever the stored
cell isNULL.- Named table-level constraints were parsed as columns. A
CREATE TABLE
body item such asCONSTRAINT pk_geom_cols PRIMARY KEY (table_name, column_name)was split on its top-level commas exactly like a real column
list, producing bogus extra "columns".is_table_constraintnow recognizes
PRIMARY KEY/UNIQUE/CHECK/FOREIGN KEY/CONSTRAINT-led body items and
skips them. - Known limitation, stated rather than hidden:
layers()covers
GeoPackage (featuregpkg, not on by default), Shapefile, and GeoJSON.
FlatGeobuf and GeoParquet returnOxiGeoError::NotSupportednaming the
unsupported driver; both remain reachable only through the streaming feature
API.
Full Changelog: v0.2.2...v0.2.3
OxiGeo 0.2.2 Release
[0.2.2] - 2026-07-30
Issue #14 fix campaign. GitHub issue #14
reported that Dataset::read_band silently ignored its band argument on
multi-band rasters, returning the whole pixel-interleaved image instead of the
requested band. Root-causing it traced back to oxigeo-drivers/geotiff's
block-decode engine (rewritten from scratch as band_read.rs/band_read/multi.rs),
then surfaced the identical defect pattern — assuming chunky
(PlanarConfiguration=1) interleaving, or the wrong byte order, wherever
multi-band raster data was read — independently re-implemented in a dozen other
crates, plus a handful of unrelated bugs found along the way. 192 files changed;
33 new issue_14_*-named files (30 regression tests, 2 benchmarks, 1 example) plus
dedicated cases embedded in the Node/ML/Jupyter/CLI suites guard against
regressions.
Changed
-
BREAKING —
oxigeo::Dataset::read_bandnow returns one band. Up to 0.2.1 it
ignored itsbandargument on multi-band rasters and returned the whole
pixel-interleaved image (width × height × bandssamples,b0 b1 b2 b0 b1 b2 …),
which silently mis-fed every caller that asked for a single band. It now returns
exactly that band'swidth × heightsamples. Single-band rasters are unaffected;
on a 3-band fileread_band(0)returns a third as many samples as it used to, so
a length check finds affected code quickly. -
BREAKING —
DatasetInfois now#[non_exhaustive]. It also gained
impl Defaultand a newdata_type: Option<RasterDataType>field (the on-disk
pixel type, readable before any raster read via the newDataset::data_type()).
Downstream struct-literal construction — evenDatasetInfo { field, .. }— no
longer compiles; build fromDatasetInfo::default()instead. -
DEFLATE tile decoding is substantially faster. The
oxiarc-*suite moves
0.3.6 → 0.4.0, which rewrites the DEFLATE/zlib decoder (two-level Huffman
root+sub-tables, a buffered bit reader with a register-resident accumulator, and
an LZ77 history that is the output buffer instead of a ring buffer written
twice), and the GeoTIFF driver now uses its new decompress-into-slice entry
point. Measured on 256×256 UInt16 DEM tiles withPREDICTOR=2— the layout used
by SRTM/Copernicus DEM COGs — decode throughput goes from 99.0 MiB/s on
oxiarc-deflate 0.3.6 to 143.7 MiB/s on 0.4.0 (1.45×), and to 177.4 MiB/s
(1.79×) throughzlib_decompress_into, which is the path a whole-band read
now takes. Whole-band DEFLATE reads additionally perform zero decode-side
allocations: one caller-owned scratch buffer serves every tile, where each tile
previously grew its ownVecby repeated doubling. Output bytes are unchanged;
the decoded-size hint is an optimisation only, and a wrong, absent, or clamped
hint falls back to the growable path rather than failing (#14).
Added
-
oxigeo::Datasetinterleaved (multi-band) readers — the supported
replacement for the pre-0.2.2read_bandbehaviour, so the breaking change above
leaves no gap:read_interleaved(bands) -> Vec<T>andread_interleaved_into(bands, dst)read_window_interleaved(bands, col, row, w, h) -> Vec<T>and
read_window_interleaved_into(bands, col, row, w, h, dst)
bandsisOption<&[u32]>:Nonemeans every band in file order (mirroring
GDAL'spanBandMap == nullptr), and a slice selects, reorders (&[2,1,0]reads
RGB as BGR), subsets (only the named bands are decoded), or repeats band indices.
The element type is converted from the file's type while the blocks are decoded,
exactly asread_band_intodoes. The*_intoforms allocate a single scratch
buffer sized to one horizontal strip of one band — not to the raster — so peak
extra memory stays bounded however large the image is; a single-band selection
delegates to theread_band_intopath and allocates nothing at all. All four
honourDataset::clip's pixel window like every other reader. -
oxigeo::Datasetgained a pre-read type query and zero-allocation
single-band/window readers:data_type() -> Option<RasterDataType>reads the
on-disk pixel type from the header before any raster read;read_band_into<T: RasterElement>(band, dst)andread_window_into<T>(band, col, row, w, h, dst)
decode straight into a caller-owned buffer (the interleaved readers above already
build on this same path).RasterElement— seeoxigeo-corebelow — is
re-exported at the crate root. -
oxigeo-coregained a typed, zero-copy raster-element layer. The sealed
RasterElementtrait (implemented foru8/i8/u16/i16/u32/i32/u64/i64/f32/f64;
Copy + Default + Send + Sync + 'static) defines each type's on-disk byte width,
RasterDataTypetag, and native-endian byte conversion, plus exact — never
lossy throughf64— integer-to-integer conversion via ani128bridge. Built
on it:convert_raw_into/convert_raw_into_with/convert_raw_bytes/
elements_as_bytes, andRasterBuffer::from_element_slice/
copy_to_slice[_with]/to_typed_vec[_with].DataSource/AsyncDataSource
gainedread_range_into/range_slicemethods (default: still allocates
internally);FileDataSourcenow issues real positional reads (pread/
seek_read) instead of serializing every read through oneMutex<File>, and
MmapDataSource/MmapDataSourceRwoverride both for true zero-copy reads
straight out of the mapping. -
oxigeo-drivers/geotiffgained a real band-aware, low-allocation read API:
band_byte_len/band_pixel_count,read_band_into/read_band_into_typed,
read_window/read_window_into/read_window_into_typed,
read_bands_into_typed/read_window_bands_into_typed(one block decode shared
across every requested band),byte_order(),level_size(level)(exact
per-overview dimensions from that level's own IFD, notfull_size / 2^level),
read_tile_band_buffer(read_tile_bufferis now itsband = 0shorthand),
CogReader::tile_decoded_size/read_tile_into, andcompression::decompress_into/
decompress_into_partial. New opt-inparallelfeature fans block decode out
across rayon workers (bit-identical to serial).
Fixed
GeoTIFF driver — the issue #14 root cause (oxigeo-drivers/geotiff)
GeoTiffReader::read_bandnever read itsbandparameter (it was named
_band). It sized its output as the whole image (width × height × bytes_per_sample × samples_per_pixel) and copied every decoded tile's raw
chunky (PlanarConfiguration=1) bytes into it 1:1 — so every band index
returned identical, full-image bytes, and aPlanarConfiguration=2(planar)
file was decoded as if it were chunky, scrambling every band. Overview levels
(level > 0) additionally walked the primary image's tile grid unconditionally.
Replaced by a purpose-built engine (band_read.rs,band_read/multi.rs): a
ReadPlan/LevelGeometryresolves each level's real geometry and planar config
once, anddecode_blockeither de-interleaves the requested band during the
scatter (chunky) or reads only that band's own blocks (planar) — the interleaved
plane is never materialized, and the band index is validated. Output is now
exactly one band'swidth × height × bytes_per_samplebytes.- The TIFF predictor (horizontal-differencing) undo used the wrong stride on
planar files.CogReader::read_tilealways passedsamples_per_pixelas the
predictor stride, but a planar block holds one band, so the correct stride is 1;
the wrong stride "subtracts the wrong neighbour from every sample… rows bleed
into each other. Nothing errors; the pixels are simply wrong." Fixed via a new
per-blockblock_samples_per_pixel(1 when planar). Separately,
Compression::Lerccombined with anyPredictoris undefined by spec — no real
encoder produces it — but the old driver reversed the predictor over
already-decoded LERC floats anyway, corrupting every sample after the first;
this combination is now a hard error instead of silent garbage. - Per-tile reads re-parsed the entire
TileOffsets/TileByteCountsarray on
every single lookup — measured at 77% (190 of 248 ms) of one band read on an
8000-strip file. A newBlockIndex(cog/block_index.rs) parses each level's
offset/count arrays once atopen()for O(1) lookups thereafter, bounded
against hostile headers. CogConverter::convert(GeoTIFF→COG) depended on the bug above — it called
the oldread_band(0, 0)specifically because it returned the whole
interleaved image, and reassembled that into its output. Fixingread_bandin
isolation would have silently truncated every multi-band conversion to one
band; the converter now reads and re-interleaves each band explicitly.tiff/ifd.rs: several direct-slice-index panics on truncated/malformed IFDs are
now typed errors.lerc_codec:serialize_nativeused a hardcoded
to_le_bytes(), silently byte-reversing output on big-endian hosts; now
to_ne_bytes().
oxigeo-core foundation
RasterBuffer::convert_tosilently corrupted largeUInt64/Int64
values. Its per-pixel path round-tripped every sample through
get_pixel/set_pixel, which decoded/encoded viaf64— exact only to 2^53 —
so e.g.(1u64 << 53) + 1silently became1u64 << 53on conversion. Fixed by
routing through an exacti128bridge.- Latent undefined behavior in
RasterBuffer::as_slice/as_slice_mut/
row_slice. They reinterpreted aVec<u8>'s pointer directly as*const T
without checking alignment (Vec<u8>only guarantees 1-byte alignment), and ran
from_raw_partson the zero-length dangling sentinel pointer for empty buffers
— UB regardless of length wheneveralign_of::<T>() > 1. It never crashed in
practice because production allocators over-align, which is exactly why i...
OxiGeo 0.2.1 Release
[0.2.1] - 2026-07-28
Production-hardening campaign (2026-07): a workspace-wide, multi-agent defect
sweep across all 76 crates surfaced 342 confirmed defects
(47 critical / 84 high / 83 medium / 33 low). 314 were fixed across 38 crate
lanes (~520 files changed); the remaining 79 were honestly deferred, each left
with a safe typed-error path — a loud Unsupported* / NotImplemented /
DecodingError rather than silent or fabricated data. Quality gates all green:
cargo fmt --check clean; cargo clippy --workspace --all-features --all-targets
0 warnings; cargo nextest run --all-features 17,723 passed / 0 failed /
100 skipped (16,307 passed / 0 failed / 79 skipped on default features); 416
doc tests passing; cargo deny check passing. The categorized list of
deferrals carried to v0.3.0 is in TODO.md.
Fixed
Format drivers
- oxigeo-jpeg2000: two CRITICAL correctness bugs fixed — multi-tile decode now
Psot-bounds each tile's bitstream and composites it at its real pixel offset
(previously every tile silently returned tile 0), and the JP2 box parser now
recurses intojp2hsoihdr/colrin spec-conformant.jp2files are read - oxigeo-geotiff: real planar-configuration (
PlanarConfiguration=2) decoding;
authoritative EPSG projected/geographic classification; a working JPEG/WebP writer
path; the silentGeoKeyDirectoryerror and a policy-violatingexpect()removed;
ausize-overflow bug in header-driven allocation fixed - oxigeo (umbrella): fixed GitHub issue #12, "Metadata missing when reading
geotif" — the lightweightextract_tiff_info()peek parser used byDataset::open()
(distinct from the fulloxigeo-geotiffdriver above) only scanned a GeoTIFF's
first 8 KiB, soModelPixelScaleTag/ModelTiepointTag/GeoKeyDirectoryTagvalues
stored out-of-line past that offset — routine for striped TIFFs with many strips —
were silently treated as absent andcrs()/geotransform()/bounds()all returned
Noneeven though the tags were present and well-formed; the peek buffer now
extends up to a bounded 1 MiB when a georeferencing tag's value lands past the
initial window, a Y-axis sign inversion in the derivedGeoTransformis fixed
(ModelPixelScaleTag's Y scale is a positive magnitude per spec but
GeoTransform::north_upexpects a negativepixel_height), andbounds()—
previously hardcoded toNone— is now derived from the geotransform and raster
dimensions; regression testtest_issue_12_far_offset_georeferencingadded - oxigeo-drivers/grib: CRITICAL DRT 5.40 silent-corruption bug fixed — the GRIB2
decoder now dispatches on the Data Representation Template number, so a
JPEG2000/PNG/CCSDS payload can never fall through to the simple-packing
bit-unpacker; DRT 5.40 is wired to a real Pure-Rust JPEG2000 decode via
oxigeo-jpeg2000(new default-onjpeg2000feature) - oxigeo-shapefile (vector drivers): the Polygon reader now reconstructs
multi-part polygons by ESRI ring winding (clockwise = exterior, CCW = hole) with
containment-based hole assignment, emittingMultiPolygonfor multiple exteriors —
a two-island country shapefile round-trips instead of merging its rings - oxigeo-drivers/netcdf & oxigeo-drivers/hdf5: NetCDF-4 reader now recurses
into HDF5 sub-groups (was silently dropping their variables); the HDF5 writer's
chunking/compression/fill-value hints are no longer silently dropped (real chunked
write path plus honest errors for shapes oxih5 cannot represent); real object-header
parsing sodecode_chunk/filter-pipeline/chunking are no longer dead code - oxigeo-drivers/netcdf & oxigeo-drivers/hdf5: attribute decoding now trusts
the dataspace-declared element count (count × dtype_size) and ignores trailing
bytes, so scalar/small numeric attributes written with padded payloads no longer
decode as phantom extra elements — this silently disabled CF_FillValue/
scale_factorhandling for files written by oxih5 0.2.1, whoseFileWriterpadded
sub-8-byte scalar attribute payloads; the writer regression is now root-fixed
upstream in oxih5 0.2.2 (this workspace is pinned to it), and the defensive trim
stays in place as a belt-and-suspenders guard against older files written by 0.2.1 - oxigeo-drivers/geoparquet: XYZ/XYM geometry decode ambiguity fixed
Algorithms & CRS
- oxigeo (umbrella): CRITICAL
Dataset::clip()bug fixed — clip now records a
pixel window that every raster read (read_band/bands/statistics/convert/
read_window) crops the source file to, so a clipped dataset no longer silently
reprocesses the full raster - oxigeo-algorithms: real NEON SIMD (with scalar-parity tests) for morphology
(3×3 erode/dilate) and threshold kernels; a real CSE (let-binding hoisting) + DCE
(liveness/reachability) pass for the raster-algebra optimizer - oxigeo-proj: PROJ
+proj=hgridshift/+proj=vgridshiftpipeline steps now
actually apply a grid — newGridRegistry+Pipeline::with_hgrid/with_vgridand
evaluators calling the crate's NTv2 grid parser (a sign bug in it was fixed)
Server & OGC services
- oxigeo-server: the
/tiles/{layer}/{z}/{x}/{y}.{fmt}XYZ endpoint now renders
real raster data — reads the intersecting source window, reprojects Web-Mercator
tiles into the dataset's native CRS (per-pixel inverse warp for non-3857 data),
applies the layer colormap/RGB style, and masks off-dataset/nodata pixels as
transparent — replacing a hard-coded checkerboard - oxigeo-services: WPS
buffer/clip/unionnow perform real geometry math via
oxigeo-algorithmsand return the computed GeoJSON (previously ignored their
inputs); CQL2 gained!=/<>,IN (...), andIS [NOT] NULL
Query engine
- oxigeo-query / oxigeo-index: JOIN output now preserves native column types
instead of stringifying everything; SELECT projection lists are actually applied;
HAVING is executed (including aggregates referenced only by HAVING); the WHERE
evaluator gainedBETWEEN/IN/CASE/CASTwith real type coercion
ML
- oxigeo-ml: model pruning/quantization no longer corrupts ONNX files — a real
ONNX protobuf walker (optimization/onnx_weights.rs) applies genuine tensor
transforms;ModelVersionOrdbug fixed - oxigeo-ml-foundation: the crate now compiles and trains — a genuine trainable
scirs2-neural backend (real forward/backward/optimizer step with explicit gradient
routing) replaces code that referenced removedrandAPIs and mismatched types
Cloud & DB connectors
- oxigeo-postgis:
Transaction::dropnow issues a real implicitROLLBACK
(was a log-only message that leaked locks) with a double-take guard - oxigeo-db-connectors: MySQL/TimescaleDB SQL-injection surfaces closed via a new
crate::sqlidentifier-quoting/literal-escaping module plus parameter binding - oxigeo-cloud: CRITICAL rs3gw tokio nested-runtime panic fixed; byte-range reads,
the prefetch I/O driver, OAuth2/SAS credential refresh (HttpBackend), and STAC fixes - oxigeo-cloud-enhanced: fabricated Azure (Cost/Monitor/ML/Synapse) and GCP (Vertex
AI/Dataflow/Cost) clients replaced with real, bearer-token-authenticated REST clients
behind the existingazure/gcpfeatures — Azure Cost Management queries/forecasts/
budgets/Advisor, Azure Monitor metrics/Log Analytics/alerts/diagnostic settings, Azure
ML v2 control-plane compute/model/endpoint/job management, Synapse SQL/Spark pool (ARM)
management and Spark job/pipeline submission (Livy); GCP Dataflow template launch with
job status/list/metrics/cancel/drain, Vertex AI model/endpoint/training/batch-prediction
(long-running-operation polling), and GCP Cost Management via BigQuery billing export
plus Cloud Billing budgets/Recommender — every previously-fabricated success/ID/
empty-list is now a real call or an honest typedNotImplemented. True data-plane
operations a control-plane REST client can't mint stayNotImplemented(Monitor
metric/diagnostic ingestion, Cost alert/export, Synapseexecute_query, ML
invoke_endpoint, GCP cost forecast/export)
HA & infra
- oxigeo-ha: PITR, snapshot, backup, and DR were entirely fabricated (canned bytes,
always-pass tests) — replaced with real WAL + on-disk persistence and injectable
executors; a genuine Raft log-replication module (failover/log_replication.rs) with
AppendEntriesconsistency check, conflict truncation, and majority commit added - oxigeo-cluster (cluster-dist): leader heartbeats now travel over the transport to
followers (realAppendEntries-style RPC + handler) so followers stop perpetually
re-running elections; W-TinyLFU is now reachable and used by the multi-tier cache - oxigeo-kinesis / oxigeo-kafka / oxigeo-pubsub: fake/no-op broker paths
replaced with real implementations and honest errors — Firehose transformation now
actually happens; Kafka read-process-write exactly-once wired to real transactions
Bindings
- oxigeo-node: multi-band GeoTIFF save (BIP interleave round-trip); GeoJSON parser
handles every geometry type;CancellationTokenwired into batch/parallel processors
doing real chunked multi-threaded per-pixel work - oxigeo-jupyter:
%crs/%bounds/%statsnow read a real parsed GeoTIFF dataset
instead of returning hard-coded"(example)"literals - oxigeo-python:
open_raster/create_rasterno longer silently discard the
driver/optionsarguments — a real remote/cloud data-source layer (remote.rs)
wiresdriver="COG"and S3/HTTP options through tooxigeo-cloud
no_std & platform
- oxigeo-core / oxigeo-embedded: the no_std/embedded claim is now real
end-to-end — both crates genuinely cross-compile for bare-metal
thumbv7em-none-eabihf(Cortex-M4) andriscv32imac-unknown-none-elf(verified with
actual--targetb...
OxiGeo 0.2.0 Release
[0.2.0] - 2026-07-20
Changed
-
Project renamed: OxiGDAL → OxiGeo. Version 0.2.0 is functionally
identical to 0.1.7 — this is a rename-only release with no feature or
behavior changes beyond identifiers. The GitHub repository has moved to
https://github.com/cool-japan/oxigeo (oldoxigdalURLs redirect), and
v0.1.7 remains the final release published under the OxiGDAL name.Migration table (old → new):
Area Old (OxiGDAL) New (OxiGeo) Crates (all 74 published) oxigdal,oxigdal-<name>oxigeo,oxigeo-<name>CLI binary oxigdaloxigeoEnvironment variables OXIGDAL_*(e.g.OXIGDAL_CONFIG,OXIGDAL_HOST,OXIGDAL_PORT,OXIGDAL_WORKERS,OXIGDAL_LOG_LEVEL,OXIGDAL_DATA_DIR,OXIGDAL_CACHE_DIR)OXIGEO_*(OXIGEO_CONFIG,OXIGEO_HOST,OXIGEO_PORT,OXIGEO_WORKERS,OXIGEO_LOG_LEVEL,OXIGEO_DATA_DIR,OXIGEO_CACHE_DIR)Python PyPI package oxigdal;import oxigdal; native moduleoxigdal._oxigdalPyPI package oxigeo;import oxigeo; native moduleoxigeo._oxigeonpm @cooljapan/oxigdal;@cooljapan/oxigdal-node(+ platform packages);@cooljapan/oxigdal-geoparquet@cooljapan/oxigeo;@cooljapan/oxigeo-node(+ platform packages);@cooljapan/oxigeo-geoparquetC / mobile FFI symbol prefix oxigdal_; JNI classcom.cooljapan.oxigdal.OxiGDAL; headeroxigdal_mobile.h; include guardOXIGDAL_MOBILE_Hsymbol prefix oxigeo_; JNI classcom.cooljapan.oxigeo.OxiGeo; headeroxigeo_mobile.h; include guardOXIGEO_MOBILE_HRust API types OxiGdal*prefixed types (e.g.OxiGdalError)OxiGeo*(OxiGeoError)WASM artifacts oxigdal_wasm*; napi artifactoxigdal.<triple>.nodeoxigeo_wasm*; napi artifactoxigeo.<triple>.nodeContainer images oxigdal/*; systemd unitoxigdal-server.serviceoxigeo/*; systemd unitoxigeo-server.serviceRuntime identifiers HTTP User-Agent OxiGDAL/1.0; Kafka consumer groupoxigdal-etl; ETL checkpoint diroxigdal-checkpoints; edge cache dir.oxigdal_cache; attestation format idoxigdal-attestationHTTP User-Agent OxiGeo/1.0(theoxigeo-stac/oxigeo-mlagents now report0.2.0); Kafka consumer groupoxigeo-etl; ETL checkpoint diroxigeo-checkpoints; edge cache dir.oxigeo_cache; attestation format idoxigeo-attestation -
The
oxigdal-*0.1.x crates remain published on crates.io for existing
users; theoxigeo-*crates supersede them starting with 0.2.0.
Full Changelog: v0.1.7...v0.2.0
OxiGDAL 0.1.7 Release
[0.1.7] - 2026-07-20
Added
- oxigdal-cloud-enhanced: real Azure IMDS managed-identity tokens via
azure_identity::ManagedIdentityCredential, replacing the placeholder-token stub; real GCP metadata-server access/identity tokens plus IAM Credentials API impersonation, withGCE_METADATA_HOSToverridable for mock-server tests - oxigdal-cloud: multicloud
build_backend()factory (S3/GCS/AzureBlob/Http, feature-gated) with a backend cache;get/put/delete/exists_in_providerare now functional against real backends - oxigdal-drivers-advanced: JPEG2000 decode now delegates to
oxigdal-jpeg2000for real decode with full header parsing, replacing the gray-placeholder-pixel stub - oxigdal-services: WFS-T Memory/File transactions fully implemented — insert/update/delete/replace with per-path write serialization
- oxigdal-services: WCS File/Url/Memory coverages now do real GeoTIFF read/write via
oxigdal-geotiff;encode_as_geotiffproduces real GeoTIFF bytes (was stub output) - oxigdal-ml-foundation:
onnx_export.rs— pure-Rust ONNX protobuf encoder (ir_version 8, opset 13), round-trip-validated againstoxionnx - oxigdal-ml-foundation: augmentation noise generation now uses real Gaussian sampling (
scirs2_coreseeded RNG) instead of a synthetic pattern - oxigdal-ml:
OnnxModel::infer_multiband— real multi-channel[1, C, H, W]NCHW tensor inference over aMultiBandBuffer(band-sequential channel order, unpacked back into one output band per channel); previouslyinferaccepted only a single-bandRasterBuffer - oxigdal-workflow: Temporal/Prefect
import_workflowround-trips exporter-generated definitions via metadata headers for lossless ID recovery; export now emits real activity bodies - oxigdal-etl:
calculate_ndvimap transform implemented, with a zero-denominator guard so masked/no-data pixels emit0.0rather thanNaN - oxigdal-cli:
info/statsimplemented for FlatGeobuf, GeoParquet, Zarr, GeoPackage, JPEG2000, COPC, PMTiles, MBTiles (previously "not yet implemented") - oxigdal-algorithms: Lanczos resampling
WrapandMirroredge modes implemented (rem_euclid/ reflect-101) - oxigdal-geojson-stream: TopoJSON writer now emits real arcs for LineString/MultiLineString — open-chain topology with endpoint junctions, no-rotation splitting, and shared-arc dedup via negative reversed indices (was an empty
"arcs": []stub) - oxigdal-gpu: subgroup/warp operations emit native WGSL subgroup builtins with a workgroup-shared-memory emulation fallback; Metal filter/reduction/nearest-neighbor shader generators implemented; ballot/vote/
SimdGroupOperationsupgraded; new execute-and-compare GPU tests (verified on Metal) - oxigdal-bench: raster/io scenarios now do real work (tile reads,
MmapDataSource) instead of synthetic placeholders - oxigdal-wasm:
WasmCogViewer.openBytes— drag-drop local GeoTIFF with full codec support including LZW/Zstd viaCogReader<MemorySource>;readTileElevation(SampleFormat tag 339 parsing);WasmTerrain— hillshade/multidirectional hillshade/slope/aspect/color-relief-shaded (Horn method,ImageDataoutput);WasmProjection+wgs84ToWebMercator/webMercatorToWgs84shims - GeoLab demo (
demo/cog-viewer): rebranded OxiGDAL GeoLab — drag-drop loading, terrain-analysis panel, honest byte counters, all CDN dependencies vendored locally; staged to cooljapan.tech/geolab/ (deploy manual) - oxigdal-security: new
attestationmodule — tamper-evident session ledger: domain-separated blake3 hash chain (SessionLog), Merkle root + per-entry inclusion proofs, Ed25519 session seal (SessionSigner::seal), andverify_attestation()re-verifying chain/root/signature from the attestation JSON alone; golden-fixture and tamper-detection tests; native skeptic's verifier exampleverify_attestation.rs; compiles for wasm32 under--no-default-features --features attestation - oxigdal-wasm:
sentinelmodule (GeoSentinel) —WasmStacClientEarth Search STAC scene-pair search with client-side cloud/nodata/grid filtering; self-contained UTM↔WGS84 (Krüger series, EPSG 326xx/327xx);GeoSentinelchange-detection pipeline: windowed COG reads → BOA offset → NDVI drop → fixed/Otsu threshold → polygonization → Karney geodesic hectares → GeoJSON, plus true-color and diff-heatmap RGBA overlays - oxigdal-wasm:
vaultmodule (GeoVault) —WasmVaultSessionblake3 hash-chained operation log sealed with Ed25519 into attestation JSON,verifyAttestation, blake3fileDigestHexfor dropped files - oxigdal-wasm:
anomalymodule — self-contained Z-score / IQR / modified-Z-score / percentile / σ-bounds detectors (parity-ported fromoxigdal-analytics/oxigdal-qc) with mask,ImageData, and summary-JSON outputs - oxigdal-wasm: COG reader overview-level reads — full per-overview IFD parsing (each level gets its own tile directory, predictor, and sample layout),
read_tile_level, andread_window_u16/read_window_rgb8window assembly; PREDICTOR=2 horizontal-differencing undo (TIFF tag 317) for u8/u16 samples on all tile and window paths - oxigdal-geoparquet: new
plan/pushdownAPIs —plan_pushdown()computes row-group bbox + attribute-statistics pruning and exact column-chunk byte ranges from metadata alone (zero I/O);execute_pushdown()runs pushdown over anyparquet::ChunkReader(GeoParquetReader::read_pushdownis now a thin wrapper) - oxigdal-geoparquet: bbox-column detection now honors GeoParquet 1.1
covering.bboxpaths from thegeometadata (authoritative) with a plainbboxstruct-root fallback — VIDA-style files (5.9 GB / 9,533 row groups) now prune correctly - oxigdal-geoparquet:
AttributeFilter::Cmpscalar comparisons (>,>=,<,<=,<>) with Int64/Float64 literal↔column coercion (a bare integer compares correctly against a Float64 column and a whole-valued decimal against an integer column); multiple filters compose as a conjunction viawith_attribute_filters - oxigdal-wasm-geoparquet (new crate): browser GeoParquet range-request client — remote footer decode,
SparseChunkReaderover prefetched byte ranges, 64 KiB-gap range coalescing, SQLWHERE-fragment → predicate lowering (sqlparser, typed rejections naming unsupported constructs),RecordBatch→ GeoJSON conversion, andRemoteGeoParquetopen/plan/query with byte and request accounting (npm:@cooljapan/oxigdal-geoparquet) - GeoSentinel demo (
demo/geosentinel): in-browser Sentinel-2 change detection — STAC pair search, streamed COG windows, NDVI-drop polygons with geodesic hectares, GeoJSON export, before/after crossfade; staged to cooljapan.tech/geosentinel/ (deploy manual) - GeoVault demo (
demo/geovault): sovereign clean-room workstation — CSP-enforced zero egress, live session ledger, seal → attestation download, independentverify.htmlverifier; synthetic Site K-7 DEM via newoxigdal-geotiffexamplegeovault_scene.rs; staged to cooljapan.tech/geovault/ (deploy manual) - GeoParquet Live demo (
demo/geoparquet): bounding-box + SQL attribute queries against the 5.9 GB VIDA GeoParquet via predicate pushdown over HTTP ranges — row-group strip visualization, plan-cost preview before any fetch, Cache API footer caching, offline sample + newoxigdal-geoparquetexamplegenerate_sample.rs; staged to cooljapan.tech/geoparquet/ (deploy manual) - oxigdal-server: new example
render_hero.rs(DEM → combined hillshade → colormap → PNG) - docs.rs metadata added to all 64 remaining publishable crates (21 curated for Pure-Rust-only docs builds)
- New
CONTRIBUTING.mdandCODE_OF_CONDUCT.md
Changed
- oxigdal-cloud-enhanced:
reqwestmade optional, gated behind thegcpfeature - oxigdal-ml-foundation: weights save/load moved to
oxicode(COOLJAPAN no-bincode policy) - oxigdal-services: Database transactions/feature-sources/SQL count moved behind new non-default
postgisfeature (oxigdal-postgispool,ST_GeomFromGeoJSON/ST_AsGeoJSON); WCSUrlcoverage fetch moved behind new non-defaultremotefeature - oxigdal-drivers-advanced:
jpeg2000feature is now dependency-gated (pulls inoxigdal-jpeg2000only when enabled) - oxigdal-security: dependencies split behind new
enterprise/tls/attestationfeatures (default enables all three) — the heavyweight server-side surface (tokio, dashmap, petgraph, scirs2-core, oxiarc-zstd, regex, parking_lot, uuid, chrono, crypto stack) is now optional underenterprise;tlsimpliesenterprise;attestationpulls onlyblake3+ed25519-dalek, keeping the wasm32 surface lean - GeoLab demo: shared
@cooljapan/oxigdalWASM package rebuilt (pkg refresh) — GeoLab, GeoSentinel, and GeoVault all serve the same refreshed package - Examples/benches reorganized: 31 orphaned top-level examples wired into
oxigdal-examples(API rot fixed, 5 duplicates pruned); 11 benches wired intooxigdal-bench - README: stats refreshed, doc links updated, GeoLab hero image made clickable, new
## Demosection with native-render gallery (docs/media/); section grown to## Demoswith hero/GIF/gallery/honest-notes blocks for GeoSentinel, GeoVault, and GeoParquet Live - Dependencies bumped to latest per the Latest Crates Policy:
oxiproj/oxiproj-core0.1.1 → 0.1.2,oxisql-core/oxisql-sqlite-compat0.3.2 → 0.4.0,oxinetcdf0.1.4 → 0.2.0,oxih50.1.4 → 0.2.0 — version-onlyCargo.tomlchanges; theoxih5/oxinetcdfjump to 0.2.0 was verified source-compatible with theoxigdal-drivers/hdf5/oxigdal-netcdfdriver code (no driver-side changes required)
Fixed (production-hardening campaign, 2026-07)
Parallel multi-lane defect sweep across the workspace: 233 verified defects fixed across
69 crates (correctness, unwrap-elimination, clippy, doc/README accuracy). Headline items:
Format drivers
- oxigdal-geotiff: floating-point predictor (TIFF `Predictor=3...
OxiGDAL 0.1.6 Release
[0.1.6] - 2026-06-15
Added
- oxigdal-shapefile: Non-UTF-8 DBF encoding support via
encoding_rs(CPG/LDID, PR #10) - oxigdal-proj:
wkt_to_proj_string()— WKT-1/WKT-2 to PROJ string conversion (PR #9) - oxigdal-analytics: permutation-based significance testing for Local Moran's I
- oxigdal-cache-advanced: W-TinyLFU eviction policy + Count-Min Sketch frequency estimator
- oxigdal-copc:
WaveformPacket— LiDAR point-format 9/10 full-waveform data types - oxigdal-drivers/hdf5: HDF5 v2/v3 superblock parser with Jenkins lookup3 checksum
- oxigdal-index: Delaunay triangulation (Bowyer-Watson) + convex hull
- oxigdal-qc:
BatchRunner,GpkgValidator,StacValidator,RadiometricValidator - oxigdal-sensors: Gaussian Maximum Likelihood Classifier
- oxigdal-streaming:
KvStateBackend— OxiStore-backed persistent state backend - oxigdal-terrain: GLCM textures, TPI variants, geomorphons, cost-distance/LCP
- oxigdal-temporal: Whittaker smoother + Savitzky-Golay filter
- oxigdal-metadata: DOI/INSPIRE metadata transform (
transform_doi_locator()) - oxigdal (umbrella): GPX, KML, TopoJSON format support in
open()/ vector streaming
Changed
- SQLite backend:
rusqlite/libsqlite3-sys(C FFI) fully replaced byoxisql-sqlite-compat 0.1.5(pure-Rust Limbo engine) - oxigdal-security: TLS migrated to
oxitls-core+oxitls-adapter-rustls-rustcrypto(100% Pure Rust default) scirs2suite 0.4.4 → 0.5.0;oxiarc-*0.3.0 → 0.3.3;oxicode0.2.3 → 0.2.4;oxionnx0.1.3 → 0.1.4- MSRV raised 1.85 → 1.89
Fixed
- Pure Rust Policy:
ring,rusqlite,rdkafka-sysremoved from default feature closure — workspace default build is 100% C/FFI-free
Full Changelog: v0.1.5...v0.1.6
OxiGDAL 0.1.5 Release
Full Changelog: v0.1.4...v0.1.5
OxiGDAL 0.1.4 Release
Full Changelog: v0.1.3...v0.1.4
OxiGDAL 0.1.3 Release
Full Changelog: v0.1.2...v0.1.3