lerc-rs
Pure Rust implementation of LERC (Limited Error Raster Compression), Esri's open format for fast, efficient raster encoding with controlled precision loss.
Supports encoding and decoding of LERC2 (v2–v6) and decoding of legacy LERC1, with all 8 data types, validity masks, multi-band, multi-depth, and NoData values.
Features
- Pure Rust — no C/C++ dependencies, no unsafe code
no_std+alloccompatible — works on native andwasm32-unknown-unknown- All data types —
i8,u8,i16,u16,i32,u32,f32,f64 - Lossless and lossy — configurable
Precisionper encode - Complete codec — Huffman coding, float-point lossless (FPL) with byte-plane predictors, tiled micro-block encoding, bit-plane compression, diff encoding for multi-depth, validity masks, NoData
- Byte-for-byte identical output to the C++ reference at the same settings
- Competitive with C++ reference implementation on encode and decode
Performance
Preliminary benchmarks on a single synthetic dataset (512×512, Apple M-series, --release). Performance will vary with data characteristics; these numbers are indicative, not comprehensive.
| Path | Rust | C++ reference |
|---|---|---|
| encode f32 lossy (tolerance=0.01) | 1.9 ms | 3.1 ms |
| encode f32 lossless (FPL) | 8.3 ms | 17 ms |
| encode u8 lossless (Huffman) | 2.3 ms | 2.7 ms |
| decode f32 lossy | 0.77 ms | 0.76 ms |
Compression output is byte-for-byte identical to the C++ reference at the same settings. Run cargo bench --bench codec to reproduce (requires a C++ toolchain for the reference comparison).
Usage
[]
= "0.1"
Encode
use ;
use BitMask;
// Encode a 256×256 f32 raster with 0.01 precision
let pixels: = vec!; // your data here
let blob = encode_slice.unwrap;
// Lossless encoding (works for any type)
let bytes: = vec!;
let blob = encode_slice.unwrap;
Decode
// Decode to typed data
let = .unwrap;
// The decoder returns `BitMask::AllValid(n)` when every pixel is valid,
// so `is_all_valid` is O(1) — handy for short-circuiting NaN-write loops.
if !mask.is_all_valid
// Or decode to Image for full metadata
let image = decode.unwrap;
println!;
Zero-copy decode
// Decode into a pre-allocated buffer
let info = decode_info.unwrap;
let mut output = vec!;
let result = decode_into.unwrap;
With validity mask
use Precision;
use BitMask;
let mut mask = new;
mask.set_valid; // mark specific pixels as valid
// ... set more pixels valid ...
let blob = encode_slice_masked.unwrap;
Supported formats
| Format | Encode | Decode |
|---|---|---|
| LERC2 v6 (current) | Yes | Yes |
| LERC2 v3–v5 | Yes (auto-selects minimum version) | Yes |
| LERC2 v2 | — | Yes |
| LERC1 (legacy) | — | Yes |
Encoder features
- Tiled micro-block encoding with adaptive block size (8×8 or 16×16)
- Huffman coding for 8-bit types with delta prediction
- Float-point lossless (FPL) with byte-plane Huffman and predictors
- Diff encoding between depth slices for multi-depth data
- Bit-plane compression for noisy integer data (opt-in via negative
tolerance) precision optimizationfor float data with limited precision- NoData value encoding for mixed valid/invalid multi-depth pixels
Building
wasm
Tests run on wasm32-wasip1 via wasmtime:
Compile-only check for wasm32-unknown-unknown (no test runner):
C++ cross-validation
The test suite includes bidirectional cross-validation against the C++ reference (compiled via the lerc-cpp-ref workspace crate):
License
Apache-2.0, matching the Esri LERC reference implementation.