Skip to content

frames-sg/j2k

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

979 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

J2K — Pure-Rust JPEG 2000 and HTJ2K Codec

crates.io docs.rs CI downloads license

Docs & guides: Pure-Rust JPEG 2000 codec documentation

Release status: 0.7.3 is published and security-supported. See the release notes and release policy.

Safe public Rust APIs, audited unsafe boundaries, and vendor-independent JPEG 2000 / HTJ2K.

J2K is a Rust image-codec workspace for JPEG 2000 / HTJ2K decode, encode, recode, and JPEG-to-HTJ2K coefficient-domain transcoding. It is built for teams that need safe Rust integration for untrusted still-image inputs, permissive MIT/Apache-2.0 licensing, and optional acceleration across both CUDA and Apple Metal without making a GPU vendor SDK the public API.

Speed matters, but it is not the reason this project exists. The strategic gap is a memory-safety-oriented Rust codec with a portable CPU baseline, multi-vendor GPU adapters, explicit support boundaries, and reproducible benchmark gates. The public crate release centers on j2k, with lower-level crates for native codec internals, device adapters, JPEG input, and transcode pipelines.

The codec support claim is intentionally scoped and explicit: full JPEG 2000 Part 1 codestream support for still-image workflows, JP2 wrapping, HTJ2K Part 15 codestream support, and JPH wrapping. JPX / JPEG 2000 Part 2 extensions are outside this claim unless a feature is required for standard JP2/JPH still-image correctness. The living support boundary is docs/public-support.md.

The APIs are general codec APIs. Whole-slide imaging and DICOM tile workloads are the main public examples and benchmark fixtures because they stress large tiled images, strict color handling, and high-throughput GPU paths, but the decoder, encoder, and transcode crates are not WSI-only. The digital-pathology workflow audit defines the container, indexing, color, memory, and validation responsibilities that remain outside the codec layer.

Why J2K exists

JPEG 2000 is still common in medical imaging, geospatial imagery, digital preservation, and large tiled-image systems, but the implementation landscape forces awkward tradeoffs:

Option Tradeoff J2K avoids
NVIDIA CUDA JPEG 2000 runtime CUDA/NVIDIA GPU stacks are a good fit for NVIDIA-only deployments, but not for portable Rust applications that also need Metal or CPU-first operation.
OpenJPEG Mature C implementation and useful comparator, but C codecs keep memory-safety risk on the adopter.
Grok Capable C++ JPEG 2000 / HTJ2K implementation, but AGPL licensing is not usable for every commercial or embedded integration.

J2K's intended position is different: a safe Rust public API, isolated unsafe boundaries for FFI/GPU work, no active runtime dependency on NVIDIA's JPEG 2000 runtime, strict errors for unsupported device routes, and dual MIT/Apache-2.0 licensing.

Memory Safety Posture

J2K is designed for safe Rust integration with untrusted image inputs. The public codec API is safe Rust. Unsafe code is isolated at audited FFI, GPU integration, architecture-specific SIMD/intrinsic, allocation, and bounded pointer/buffer boundaries, where inputs are validated and unsupported shapes fail with errors. The exhaustive inventory is maintained in docs/unsafe-audit.md.

This is an engineering posture backed by an explicit unsafe inventory, tests, fuzzing, and review—not a formal proof that all implementation defects are impossible. It is also not a claim that every malformed codestream is accepted or that every device path is faster than CPU. CPU remains the portable correctness baseline; GPU acceleration is promoted only for measured paths.

Quickstart

Use the public Rust API for application integration:

cargo add j2k

Run the command-line tool for quick inspection and JPEG-to-HTJ2K transcode smoke tests:

cargo install j2k-cli
j2k inspect input.jp2
j2k transcode input.jpg output.j2k --htj2k --lossless-53

Runnable repository examples:

Runtime backend selection defaults to Auto: CPU remains the portable baseline, and Metal or CUDA paths are selected only for supported shapes with validation and benchmark evidence. Single-frame HTJ2K host-output encode stays CPU by default; resident Metal encode performance claims are batch claims. Explicit device requests are strict. Unsupported device shapes return errors instead of silently changing the requested backend. Auto is an optimization policy, not a promise to use a device whenever one is available.

CUDA paths use J2K-owned CUDA Oxide device kernels through cuda-runtime. NVIDIA performance claims require self-hosted benchmark evidence; hosted CI is not treated as NVIDIA performance evidence.

High-throughput owned batches

The additive owned-batch API accepts EncodedImage values containing an Arc<[u8]> and one of Full, Region, Reduced, or RegionReduced. It prepares inputs concurrently, keeps unlike output shapes in separate groups without padding, and returns source indices, indexed preparation failures, and homogeneous group execution failures. Representable Gray, RGB, and RGBA groups use exact native U8, U16, or I16 storage in NCHW or NHWC order; float conversion and normalization are deliberately not codec operations.

Preparation can retain either a PreparedHtj2kPlan or a PreparedClassicPlan with per-tile packet, code-block, and destination geometry. Both plans reference compressed payload ranges inside the original Arc<[u8]>; neither duplicates the codestream. CpuBatchDecoder consumes single- and multi-tile plans without reparsing. Inputs outside the retained-plan boundary can remain metadata-only and use the broader CPU codec when that path supports them.

j2k-cuda and j2k-metal own persistent accelerator sessions, resident output, and validated caller-owned destinations. Their direct final stores produce the requested native dtype and layout in the destination allocation, so decoded pixels do not make a GPU-to-CPU-to-GPU round trip. The codec-wide support boundary is maintained in docs/public-support.md; the exact experimental Burn adapter boundary is maintained in docs/j2k-ml.md. Dated hardware validation and performance results live only in docs/benchmark-evidence.md.

j2k-ml is only the thin Burn allocation and synchronization adapter over these codec sessions. Readers such as wsi-rs remain responsible for finding and supplying encoded image bytes. Codec support and correctness do not by themselves constitute a speedup claim.

Which crate should I use?

Use cargo add j2k for JPEG 2000 / HTJ2K application code. Lower-level j2k-* crates remain public implementation and integration crates.

Use lower-level crates only when you need a specific integration point:

Need Crate
JPEG 2000 / HTJ2K inspect, decode, encode, and recode j2k
Shared traits and backend types j2k-core
Shared encode-stage contracts j2k-types
Shared codec constants and pure helper algorithms j2k-codec-math
JPEG inspect/decode and fixture/fallback encode j2k-jpeg
Native JPEG 2000 and HTJ2K codec engine j2k-native
JPEG-to-HTJ2K coefficient-domain transcode j2k-transcode
CUDA adapters j2k-jpeg-cuda, j2k-cuda, j2k-transcode-cuda
Metal adapters j2k-jpeg-metal, j2k-metal, j2k-transcode-metal
Burn 0.21 native integer batch adapter j2k-ml
Tile compression codecs j2k-tilecodec
Command-line inspection and JPEG-to-HTJ2K smoke transcode j2k-cli

The names statumen and wsi-dicom are not current package names.

Support and evidence

The living codec support matrix is docs/public-support.md. The Burn batch adapter has a narrower, explicit boundary in docs/j2k-ml.md. Hardware measurements and their publication qualifications are recorded separately in docs/benchmark-evidence.md.

Fast Path For LLM-Assisted Use

For normal JPEG 2000 / HTJ2K work, start with the public codec crate:

cargo add j2k

The shared decode traits live in j2k-core and are implemented by codec crates: ImageDecode, ImageDecodeRows, TileBatchDecode, and device-surface traits.

Current backend posture

CPU is the correctness baseline. BackendRequest::Auto may return CPU-backed outputs when a device path is unavailable, unsupported, or not benchmarked for the requested shape.

GPU routing is intentionally selective. A Metal or CUDA path should be enabled automatically only when the shape is supported, parity-covered, large or regular enough to amortize dispatch and transfer costs, and backed by benchmark evidence. Small tiles, irregular packet shapes, entropy-heavy stages, and codestream assembly should remain CPU unless a measured resident path shows a net win.

Metal adapters are macOS-only and experimental. Explicit Metal requests return resident Metal surfaces or encode-stage dispatches only for supported adapter paths. Metal encode support is not a blanket end-to-end guarantee for every public encode route; unsupported explicit Metal shapes fail clearly.

CUDA adapters require a CUDA driver and adapter support. CUDA device memory surfaces are available for supported paths; unsupported explicit CUDA requests fail clearly. J2K-owned CUDA kernels are used for CUDA codec stages. NVIDIA performance claims require recorded self-hosted benchmark output.

Public API and support policy

Stable APIs are j2k, j2k-core traits and value types, j2k-jpeg, and j2k-tilecodec. Experimental APIs are the Metal adapters, CUDA adapters, transcode crates, and backend encode-stage adapter SPI.

Codec contracts include ImageDecode, decode_region_scaled_into, decode_rows, TileBatchDecode, DeviceSurface, ScratchPool, and the concrete J2kContext and j2k_jpeg::DecoderContext types. BackendRequest::Auto may return CPU output. BackendRequest::Metal and BackendRequest::Cuda are strict and fail for unsupported shapes.

Container and storage integrations should pass compatible compressed payloads through when the payload kind, dimensions, component count, bit depth, signedness, and color interpretation already match the destination requirements. Decode and re-encode only when passthrough is invalid and the source codec path is supported.

Unsupported input must fail explicitly. Error messages must avoid sensitive internal details. Unsafe Rust inventory is tracked in docs/unsafe-audit.md. Fuzzing and malformed-input tests are part of release hardening. MSRV is declared in the root manifest.

Reference files:

Benchmark and parity policy

Benchmark publication requirements are maintained in docs/benchmark-corpora.md, with current run evidence in docs/benchmark-evidence.md. Use cargo run -p xtask --features adoption -- adoption-benchmark for publication bundles and cargo run -p xtask --features adoption -- adoption-report --run-dir <run-dir> for the guarded report. OpenJPEG/Grok/CUDA/Metal/Kakadu/OpenJPH claims must use the required comparator or hardware gates described in the benchmark docs; skipped rows and emulated rows are diagnostic evidence only.

Security

Report vulnerabilities according to SECURITY.md. Codec errors should be explicit, non-sensitive, and should not silently treat unsupported input as successful decode.

License

Dual-licensed under either MIT or Apache-2.0, at your option.