Skip to content

Releases: cool-japan/oxigeo

OxiGeo 0.2.4 Release

Choose a tag to compare

@cool-japan cool-japan released this 18 Aug 11:32

[0.2.4] - 2026-08-18

Added

  • oxigeo-proj: added the unambiguous type aliases SphericalTransverseMercator (= TransverseMercator) and EllipsoidalTransverseMercator (= GaussKruger), re-exported at the crate root, so call sites can state which Earth model they mean — TransverseMercator is 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 kernel projections::tmerc_forward / projections::tmerc_inverse from projections (previously reachable only as projections::cylindrical::tmerc_*).
  • oxigeo-proj: transform now re-exports SphericalTransverseMercator and EllipsoidalTransverseMercator alongside CassineSoldner/GaussKruger/TransverseMercator, so use oxigeo_proj::transform::* surfaces the two aliases instead of forcing the longer transform::cylindrical:: path. Same std gate 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 internal File/Bytes source that implements ChunkReader, 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 to GeoParquetReader's public shape.
  • oxigeo-geoparquet: GeoParquetReader::read_geometries_optional(row_group) and GeoParquetBatchReader::extract_geometries_optional(batch) return Vec<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 core tiff::is_mask_markers(new_subfile_type, photometric) and the marker constants tiff::SUBFILE_TYPE_TRANSPARENCY_MASK / tiff::PHOTOMETRIC_TRANSPARENCY_MASK.
  • oxigeo-geotiff: CogReader::ifd_count(), CogReader::level_ifd(level) and CogReader::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 block read_tile produces at that level — the level's own TileWidth/TileLength, or ImageWidth × RowsPerStrip narrowed 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 like scan_table_by_name but applies SQLite's REAL type affinity to the result: SQLite stores a lossless 40.0 in a REAL/DOUBLE/FLOAT-declared column as the integer 40, so an untyped scan surfaces it as an Integer — the typed variant restores every such value to the equivalent Float (via restore_real_affinity, driven by the declared column types), so 40 and 40.0 read back identically, matching what every affinity-aware SQLite consumer sees. scan_table_by_name itself is unchanged and still returns raw storage classes.

Changed

  • Renamed the workspace quick-xml dependency (Cargo.toml) to the oxixml-quickxml-compat package (drop-in quick-xml 0.41 compatible shim), keeping the local dependency name quick-xml so every consuming crate (oxigeo-drivers-advanced, oxigeo-vrt, oxigeo-services, oxigeo-server, oxigeo-metadata, oxigeo-qc) required no source changes.
  • deny.toml: added a quick-xml entry to [bans].deny, scoped with wrappers = ["inferno"] for the one remaining transitive path (inferno -> pprof -> oxigeo-algorithms's dev-only pprof dependency); the direct-consumer graph is clear (cargo tree -i quick-xml -e normal --workspace is empty).
  • oxigeo-gpkg: gated GeoJSON conversion (vector::geojson_convert, and its oxigeo-geojson-stream/serde_json dependencies) behind a new geojson-convert feature, kept in default so no existing build breaks; cargo build --no-default-features (e.g. for wasm) no longer pulls in the regex family via oxigeo-geojson-stream. Consumers that already build oxigeo-gpkg with default-features = false will need to add features = ["geojson-convert"] to keep using vector::geojson_convert.
  • oxigeo-proj: the oxiproj dependency is now optional and pulled in by the std feature instead of being unconditional. Every OxiProj call site already lived in a std-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 normal now lists only byteorder, serde and thiserror. 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 for std explicitly) need no change. Migration: two trait impls — impl From<oxiproj::TransformError> for Error and impl From<oxiproj::ProjError> for Error — are now #[cfg(feature = "std")] and therefore absent from --no-default-features builds; they could not have been used there anyway, since the oxiproj types they convert from were not linked. No Error variant changed: all of them carry String, not OxiProj types. --no-default-features --features proj-db remains unsupported (it was already failing to compile before this change, for unrelated alloc prelude reasons in epsg::proj_db) — superseded later in this same release: proj-db now implies std and compiles, see Fixed below.
  • Dependency bumps: oxiproj 0.1.5 — the OxiProj authority-path correctness release, which fixes upstream the divergent EPSG authority definitions documented in the proj-db feature-invariance entry under Fixed (unit-converted ellipsoid axes, method-aware +lat_ts mapping, LCC 1SP, WGS 84-hub datum composition, prime-meridian datum chains, Molodensky-Badekas operations, PROJ's ballpark/fallback selection policy, and grid direction under PROJ_DATA) — plus routine COOLJAPAN ecosystem bumps (oxiarc, oxicode, oxih5, oxionnx, oxisql, oxistore, oxitls; the quick-xmloxixml-quickxml-compat migration has its own entry above).
  • oxigeo-gpkg: SqliteHeader gained the public field reserved_bytes: u8 (byte 20 of the SQLite database header — bytes reserved at the end of every page) and a usable_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: constructing SqliteHeader with a struct literal outside the crate now requires the extra field; code that obtains headers through SqliteReader is unaffected.
  • oxigeo-wasm: WasmCogViewer, AdvancedCogViewer and BatchTileLoader hold their cached parsed reader (see the reader-reuse fix under Fixed) in Rc/RefCell and therefore no longer implement Send/Sync. On wasm32-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 a Send/Sync bound would notice, and none exists in the workspace.

Fixed

  • oxigeo-geoparquet: GeoParquetBatchReader::extract_geometries now dispatches on the geometry column's declared encoding instead of downcasting to BinaryArray unconditionally — a GeoArrow-native file read through read_all() / next_batch() previously failed with a type_mismatch error rather than decoding.
  • oxigeo-geoparquet: null geometries no longer silently desynchronise geometries from their property rows — the new read_geometries_optional / extract_geometries_optional variants keep each null as a None at its original index (the existing null-dropping methods are unchanged).
  • oxigeo-wasm: GDAL internal-mask IFDs (NewSubfileType bit 2, or PhotometricInterpretation == 4) are no longer counted as overview levels by the browser COG reader — they share the IFD chain with the overviews, so overviewCount was 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 its level argument on the URL path; it previously called a level-0 shortcut, so every overview request silently re-read full-resolution tiles.
  • oxigeo-wasm: WasmCogViewer and AdvancedCogViewer parse 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 — for AdvancedCogViewer that 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 normalises ModelPixelScaleTag (33550) Y to its magnitude, so WasmCogViewer.pixelScaleY(), the pixelScaleY key of the metadata JSON, and the Rust pixel_scale_y field of CogMetadata / IfdMetadata are 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 the openBytes path already applied .abs(), so the same raster reported opposite signs depending on how it was loaded. Neither pa...
Read more

OxiGeo 0.2.3 Release

Choose a tag to compare

@cool-japan cool-japan released this 05 Aug 10:19

[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 warp module: WarpOptions (the parsed <GDALWarpOptions> block),
    WarpResampleAlgis_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 srs module: resolve_crs, a WKT/PROJ4/EPSG:n CRS-string resolver.
  • New source_dataset module: 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 new VrtError::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=FALSE behavior — from a real structural
    error, so a routine mosaic gap can't also mask genuine failures.
  • oxigeo-vrt gained a new dependency on oxigeo-proj to 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
    default oxigeo-vrt build.

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). New oxigeo::{Layer, LayerFeatures}, and
    oxigeo::{Feature, FieldValue, Geometry} re-exported from
    oxigeo-core::vector so reading features needs no direct oxigeo-core
    dependency.
  • New crates/oxigeo/src/layer.rs (the layers() dispatch plus the
    Shapefile/GeoJSON/GeoPackage readers) and crates/oxigeo/src/gpkg_schema.rs
    (a CREATE TABLE column/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-core 0.6.4 → 0.6.5, oxicode 0.2.4 → 0.2.5 —
    routine latest-crates-on-crates.io maintenance. oxicode 0.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::validate applied 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
    VRTWarpedDataset that carries the subClass marker but no warp block is
    still rejected, since it then has no source for any pixel.
  • Depth-aware AUTHORITY/ID resolution in WKT CRS strings. The previous
    scan returned the first AUTHORITY[...]/ID[...] node found anywhere in
    a WKT tree. In a GEOGCS, that is the node nested inside SPHEROID (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_crs now tracks bracket depth and reads only the
    direct-child AUTHORITY/ID of the root node.
  • relativeToVRT was 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 own oxigeo 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 &quot;/&amp;/&#34; as their own
    Event::GeneralRef, separate from the surrounding Event::Text; those
    events fell through the XML parser's catch-all arm and vanished. A <SRS>
    block written by this crate's own VrtXmlWriter (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 unchecked band - 1, an integer-underflow panic waiting for a caller that passed band 0;
    now checked_sub with a typed VrtError::band_out_of_range on failure.
  • The oxigeo facade opened .vrt files with a zero-filled
    DatasetInfo.
    Dataset::open routed every VRT through the generic
    fallback arm of open_raster: width()/height()/band_count() all read
    back 0 and geotransform() read back None, for a file that states all
    of them in its own header. raster_read's read_band/read_window/
    read_interleaved (and their _into forms) were also hardwired to the
    GeoTIFF path only. Dataset::open now parses the VRT header for real
    metadata via a new extract_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() is true only for NearestNeighbour
    and Bilinear. 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_vector had no GeoPackage arm at all, so every .gpkg fell through to
    an empty DatasetInfo::default(). open_vector now calls the new
    extract_gpkg_info under the (non-default) gpkg feature.
  • fid read back NULL on every GeoPackage feature. SQLite stores an
    INTEGER PRIMARY KEY column as NULL in the row's record payload and keeps
    the real value only in the row's own 64-bit rowid; naively reading the
    stored cell therefore always produced a null fid. gpkg_schema now
    detects an INTEGER PRIMARY KEY column at schema-parse time
    (rowid_alias) and substitutes the row's rowid for it whenever the stored
    cell is NULL.
  • Named table-level constraints were parsed as columns. A CREATE TABLE
    body item such as CONSTRAINT 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_constraint now recognizes
    PRIMARY KEY/UNIQUE/CHECK/FOREIGN KEY/CONSTRAINT-led body items and
    skips them.
  • Known limitation, stated rather than hidden: layers() covers
    GeoPackage (feature gpkg, not on by default), Shapefile, and GeoJSON.
    FlatGeobuf and GeoParquet return OxiGeoError::NotSupported naming 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

Choose a tag to compare

@cool-japan cool-japan released this 30 Jul 05:06

[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_band now returns one band. Up to 0.2.1 it
    ignored its band argument on multi-band rasters and returned the whole
    pixel-interleaved image (width × height × bands samples, b0 b1 b2 b0 b1 b2 …),
    which silently mis-fed every caller that asked for a single band. It now returns
    exactly that band's width × height samples. Single-band rasters are unaffected;
    on a 3-band file read_band(0) returns a third as many samples as it used to, so
    a length check finds affected code quickly.

  • BREAKING — DatasetInfo is now #[non_exhaustive]. It also gained
    impl Default and a new data_type: Option<RasterDataType> field (the on-disk
    pixel type, readable before any raster read via the new Dataset::data_type()).
    Downstream struct-literal construction — even DatasetInfo { field, .. } — no
    longer compiles; build from DatasetInfo::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 with PREDICTOR=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×) through zlib_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 own Vec by 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::Dataset interleaved (multi-band) readers — the supported
    replacement for the pre-0.2.2 read_band behaviour, so the breaking change above
    leaves no gap:

    • read_interleaved(bands) -> Vec<T> and read_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)

    bands is Option<&[u32]>: None means every band in file order (mirroring
    GDAL's panBandMap == 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 as read_band_into does. The *_into forms 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 the read_band_into path and allocates nothing at all. All four
    honour Dataset::clip's pixel window like every other reader.

  • oxigeo::Dataset gained 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) and read_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 — see oxigeo-core below — is
    re-exported at the crate root.

  • oxigeo-core gained a typed, zero-copy raster-element layer. The sealed
    RasterElement trait (implemented for u8/i8/u16/i16/u32/i32/u64/i64/f32/f64;
    Copy + Default + Send + Sync + 'static) defines each type's on-disk byte width,
    RasterDataType tag, and native-endian byte conversion, plus exact — never
    lossy through f64 — integer-to-integer conversion via an i128 bridge. Built
    on it: convert_raw_into/convert_raw_into_with/convert_raw_bytes/
    elements_as_bytes, and RasterBuffer::from_element_slice/
    copy_to_slice[_with]/to_typed_vec[_with]. DataSource/AsyncDataSource
    gained read_range_into/range_slice methods (default: still allocates
    internally); FileDataSource now issues real positional reads (pread/
    seek_read) instead of serializing every read through one Mutex<File>, and
    MmapDataSource/MmapDataSourceRw override both for true zero-copy reads
    straight out of the mapping.

  • oxigeo-drivers/geotiff gained 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, not full_size / 2^level),
    read_tile_band_buffer (read_tile_buffer is now its band = 0 shorthand),
    CogReader::tile_decoded_size/read_tile_into, and compression::decompress_into/
    decompress_into_partial. New opt-in parallel feature fans block decode out
    across rayon workers (bit-identical to serial).

Fixed

GeoTIFF driver — the issue #14 root cause (oxigeo-drivers/geotiff)

  • GeoTiffReader::read_band never read its band parameter (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 a PlanarConfiguration=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/LevelGeometry resolves each level's real geometry and planar config
    once, and decode_block either 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's width × height × bytes_per_sample bytes.
  • The TIFF predictor (horizontal-differencing) undo used the wrong stride on
    planar files.
    CogReader::read_tile always passed samples_per_pixel as 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-block block_samples_per_pixel (1 when planar). Separately,
    Compression::Lerc combined with any Predictor is 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/TileByteCounts array on
    every single lookup
    — measured at 77% (190 of 248 ms) of one band read on an
    8000-strip file. A new BlockIndex (cog/block_index.rs) parses each level's
    offset/count arrays once at open() for O(1) lookups thereafter, bounded
    against hostile headers.
  • CogConverter::convert (GeoTIFF→COG) depended on the bug above — it called
    the old read_band(0, 0) specifically because it returned the whole
    interleaved image, and reassembled that into its output. Fixing read_band in
    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_native used a hardcoded
    to_le_bytes(), silently byte-reversing output on big-endian hosts; now
    to_ne_bytes().

oxigeo-core foundation

  • RasterBuffer::convert_to silently corrupted large UInt64/Int64
    values.
    Its per-pixel path round-tripped every sample through
    get_pixel/set_pixel, which decoded/encoded via f64 — exact only to 2^53 —
    so e.g. (1u64 << 53) + 1 silently became 1u64 << 53 on conversion. Fixed by
    routing through an exact i128 bridge.
  • Latent undefined behavior in RasterBuffer::as_slice/as_slice_mut/
    row_slice.
    They reinterpreted a Vec<u8>'s pointer directly as *const T
    without checking alignment (Vec<u8> only guarantees 1-byte alignment), and ran
    from_raw_parts on the zero-length dangling sentinel pointer for empty buffers
    — UB regardless of length whenever align_of::<T>() > 1. It never crashed in
    practice because production allocators over-align, which is exactly why i...
Read more

OxiGeo 0.2.1 Release

Choose a tag to compare

@cool-japan cool-japan released this 28 Jul 16:42

[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 into jp2h so ihdr/colr in spec-conformant .jp2 files are read
  • oxigeo-geotiff: real planar-configuration (PlanarConfiguration=2) decoding;
    authoritative EPSG projected/geographic classification; a working JPEG/WebP writer
    path; the silent GeoKeyDirectory error and a policy-violating expect() removed;
    a usize-overflow bug in header-driven allocation fixed
  • oxigeo (umbrella): fixed GitHub issue #12, "Metadata missing when reading
    geotif" — the lightweight extract_tiff_info() peek parser used by Dataset::open()
    (distinct from the full oxigeo-geotiff driver above) only scanned a GeoTIFF's
    first 8 KiB, so ModelPixelScaleTag/ModelTiepointTag/GeoKeyDirectoryTag values
    stored out-of-line past that offset — routine for striped TIFFs with many strips —
    were silently treated as absent and crs()/geotransform()/bounds() all returned
    None even 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 derived GeoTransform is fixed
    (ModelPixelScaleTag's Y scale is a positive magnitude per spec but
    GeoTransform::north_up expects a negative pixel_height), and bounds()
    previously hardcoded to None — is now derived from the geotransform and raster
    dimensions; regression test test_issue_12_far_offset_georeferencing added
  • 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-on jpeg2000 feature)
  • 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, emitting MultiPolygon for 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 so decode_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_factor handling for files written by oxih5 0.2.1, whose FileWriter padded
    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=vgridshift pipeline steps now
    actually apply a grid — new GridRegistry + Pipeline::with_hgrid/with_vgrid and
    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/union now perform real geometry math via
    oxigeo-algorithms and return the computed GeoJSON (previously ignored their
    inputs); CQL2 gained !=/<>, IN (...), and IS [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 gained BETWEEN/IN/CASE/CAST with 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; ModelVersion Ord bug 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 removed rand APIs and mismatched types

Cloud & DB connectors

  • oxigeo-postgis: Transaction::drop now issues a real implicit ROLLBACK
    (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::sql identifier-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 existing azure/gcp features — 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 typed NotImplemented. True data-plane
    operations a control-plane REST client can't mint stay NotImplemented (Monitor
    metric/diagnostic ingestion, Cost alert/export, Synapse execute_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
    AppendEntries consistency check, conflict truncation, and majority commit added
  • oxigeo-cluster (cluster-dist): leader heartbeats now travel over the transport to
    followers (real AppendEntries-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; CancellationToken wired into batch/parallel processors
    doing real chunked multi-threaded per-pixel work
  • oxigeo-jupyter: %crs/%bounds/%stats now read a real parsed GeoTIFF dataset
    instead of returning hard-coded "(example)" literals
  • oxigeo-python: open_raster/create_raster no longer silently discard the
    driver/options arguments — a real remote/cloud data-source layer (remote.rs)
    wires driver="COG" and S3/HTTP options through to oxigeo-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) and riscv32imac-unknown-none-elf (verified with
    actual --target b...
Read more

OxiGeo 0.2.0 Release

Choose a tag to compare

@cool-japan cool-japan released this 20 Jul 11:58

[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 (old oxigdal URLs 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 oxigdal oxigeo
    Environment 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 module oxigdal._oxigdal PyPI package oxigeo; import oxigeo; native module oxigeo._oxigeo
    npm @cooljapan/oxigdal; @cooljapan/oxigdal-node (+ platform packages); @cooljapan/oxigdal-geoparquet @cooljapan/oxigeo; @cooljapan/oxigeo-node (+ platform packages); @cooljapan/oxigeo-geoparquet
    C / mobile FFI symbol prefix oxigdal_; JNI class com.cooljapan.oxigdal.OxiGDAL; header oxigdal_mobile.h; include guard OXIGDAL_MOBILE_H symbol prefix oxigeo_; JNI class com.cooljapan.oxigeo.OxiGeo; header oxigeo_mobile.h; include guard OXIGEO_MOBILE_H
    Rust API types OxiGdal* prefixed types (e.g. OxiGdalError) OxiGeo* (OxiGeoError)
    WASM artifacts oxigdal_wasm*; napi artifact oxigdal.<triple>.node oxigeo_wasm*; napi artifact oxigeo.<triple>.node
    Container images oxigdal/*; systemd unit oxigdal-server.service oxigeo/*; systemd unit oxigeo-server.service
    Runtime identifiers HTTP User-Agent OxiGDAL/1.0; Kafka consumer group oxigdal-etl; ETL checkpoint dir oxigdal-checkpoints; edge cache dir .oxigdal_cache; attestation format id oxigdal-attestation HTTP User-Agent OxiGeo/1.0 (the oxigeo-stac/oxigeo-ml agents now report 0.2.0); Kafka consumer group oxigeo-etl; ETL checkpoint dir oxigeo-checkpoints; edge cache dir .oxigeo_cache; attestation format id oxigeo-attestation
  • The oxigdal-* 0.1.x crates remain published on crates.io for existing
    users; the oxigeo-* crates supersede them starting with 0.2.0.

Full Changelog: v0.1.7...v0.2.0

OxiGDAL 0.1.7 Release

Choose a tag to compare

@cool-japan cool-japan released this 20 Jul 05:38

[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, with GCE_METADATA_HOST overridable 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_provider are now functional against real backends
  • oxigdal-drivers-advanced: JPEG2000 decode now delegates to oxigdal-jpeg2000 for 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_geotiff produces 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 against oxionnx
  • oxigdal-ml-foundation: augmentation noise generation now uses real Gaussian sampling (scirs2_core seeded RNG) instead of a synthetic pattern
  • oxigdal-ml: OnnxModel::infer_multiband — real multi-channel [1, C, H, W] NCHW tensor inference over a MultiBandBuffer (band-sequential channel order, unpacked back into one output band per channel); previously infer accepted only a single-band RasterBuffer
  • oxigdal-workflow: Temporal/Prefect import_workflow round-trips exporter-generated definitions via metadata headers for lossless ID recovery; export now emits real activity bodies
  • oxigdal-etl: calculate_ndvi map transform implemented, with a zero-denominator guard so masked/no-data pixels emit 0.0 rather than NaN
  • oxigdal-cli: info/stats implemented for FlatGeobuf, GeoParquet, Zarr, GeoPackage, JPEG2000, COPC, PMTiles, MBTiles (previously "not yet implemented")
  • oxigdal-algorithms: Lanczos resampling Wrap and Mirror edge 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/SimdGroupOperations upgraded; 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 via CogReader<MemorySource>; readTileElevation (SampleFormat tag 339 parsing); WasmTerrain — hillshade/multidirectional hillshade/slope/aspect/color-relief-shaded (Horn method, ImageData output); WasmProjection + wgs84ToWebMercator/webMercatorToWgs84 shims
  • 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 attestation module — tamper-evident session ledger: domain-separated blake3 hash chain (SessionLog), Merkle root + per-entry inclusion proofs, Ed25519 session seal (SessionSigner::seal), and verify_attestation() re-verifying chain/root/signature from the attestation JSON alone; golden-fixture and tamper-detection tests; native skeptic's verifier example verify_attestation.rs; compiles for wasm32 under --no-default-features --features attestation
  • oxigdal-wasm: sentinel module (GeoSentinel) — WasmStacClient Earth Search STAC scene-pair search with client-side cloud/nodata/grid filtering; self-contained UTM↔WGS84 (Krüger series, EPSG 326xx/327xx); GeoSentinel change-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: vault module (GeoVault) — WasmVaultSession blake3 hash-chained operation log sealed with Ed25519 into attestation JSON, verifyAttestation, blake3 fileDigestHex for dropped files
  • oxigdal-wasm: anomaly module — self-contained Z-score / IQR / modified-Z-score / percentile / σ-bounds detectors (parity-ported from oxigdal-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, and read_window_u16 / read_window_rgb8 window assembly; PREDICTOR=2 horizontal-differencing undo (TIFF tag 317) for u8/u16 samples on all tile and window paths
  • oxigdal-geoparquet: new plan / pushdown APIs — 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 any parquet::ChunkReader (GeoParquetReader::read_pushdown is now a thin wrapper)
  • oxigdal-geoparquet: bbox-column detection now honors GeoParquet 1.1 covering.bbox paths from the geo metadata (authoritative) with a plain bbox struct-root fallback — VIDA-style files (5.9 GB / 9,533 row groups) now prune correctly
  • oxigdal-geoparquet: AttributeFilter::Cmp scalar 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 via with_attribute_filters
  • oxigdal-wasm-geoparquet (new crate): browser GeoParquet range-request client — remote footer decode, SparseChunkReader over prefetched byte ranges, 64 KiB-gap range coalescing, SQL WHERE-fragment → predicate lowering (sqlparser, typed rejections naming unsupported constructs), RecordBatch → GeoJSON conversion, and RemoteGeoParquet open/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, independent verify.html verifier; synthetic Site K-7 DEM via new oxigdal-geotiff example geovault_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 + new oxigdal-geoparquet example generate_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.md and CODE_OF_CONDUCT.md

Changed

  • oxigdal-cloud-enhanced: reqwest made optional, gated behind the gcp feature
  • 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 postgis feature (oxigdal-postgis pool, ST_GeomFromGeoJSON/ST_AsGeoJSON); WCS Url coverage fetch moved behind new non-default remote feature
  • oxigdal-drivers-advanced: jpeg2000 feature is now dependency-gated (pulls in oxigdal-jpeg2000 only when enabled)
  • oxigdal-security: dependencies split behind new enterprise / tls / attestation features (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 under enterprise; tls implies enterprise; attestation pulls only blake3 + ed25519-dalek, keeping the wasm32 surface lean
  • GeoLab demo: shared @cooljapan/oxigdal WASM 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 into oxigdal-bench
  • README: stats refreshed, doc links updated, GeoLab hero image made clickable, new ## Demo section with native-render gallery (docs/media/); section grown to ## Demos with hero/GIF/gallery/honest-notes blocks for GeoSentinel, GeoVault, and GeoParquet Live
  • Dependencies bumped to latest per the Latest Crates Policy: oxiproj/oxiproj-core 0.1.1 → 0.1.2, oxisql-core/oxisql-sqlite-compat 0.3.2 → 0.4.0, oxinetcdf 0.1.4 → 0.2.0, oxih5 0.1.4 → 0.2.0 — version-only Cargo.toml changes; the oxih5/oxinetcdf jump to 0.2.0 was verified source-compatible with the oxigdal-drivers/hdf5/oxigdal-netcdf driver 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...
Read more

OxiGDAL 0.1.6 Release

Choose a tag to compare

@cool-japan cool-japan released this 16 Jun 07:15

[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 by oxisql-sqlite-compat 0.1.5 (pure-Rust Limbo engine)
  • oxigdal-security: TLS migrated to oxitls-core + oxitls-adapter-rustls-rustcrypto (100% Pure Rust default)
  • scirs2 suite 0.4.4 → 0.5.0; oxiarc-* 0.3.0 → 0.3.3; oxicode 0.2.3 → 0.2.4; oxionnx 0.1.3 → 0.1.4
  • MSRV raised 1.85 → 1.89

Fixed

  • Pure Rust Policy: ring, rusqlite, rdkafka-sys removed 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

Choose a tag to compare

@cool-japan cool-japan released this 22 May 07:40

Full Changelog: v0.1.4...v0.1.5

OxiGDAL 0.1.4 Release

Choose a tag to compare

@cool-japan cool-japan released this 19 Apr 14:48

Full Changelog: v0.1.3...v0.1.4

OxiGDAL 0.1.3 Release

Choose a tag to compare

@cool-japan cool-japan released this 22 Mar 00:13

Full Changelog: v0.1.2...v0.1.3