Metadata-Version: 2.4
Name: cft-jpegls
Version: 0.1.0a1
Classifier: Development Status :: 3 - Alpha
Classifier: Programming Language :: Rust
Classifier: Programming Language :: Python :: 3
Requires-Dist: numpy>=2,<3
Requires-Dist: maturin>=1.9,<2 ; extra == 'release'
Requires-Dist: twine>=6 ; extra == 'release'
Requires-Dist: pytest>=8 ; extra == 'test'
Requires-Dist: imagecodecs>=2025.3.30 ; extra == 'test'
Provides-Extra: release
Provides-Extra: test
License-File: LICENSE
License-File: vendor/jpegls-rs/LICENSE
Summary: Xerra's native Rust grayscale JPEG-LS decoder with parallel chunk decoding
Author: Xerra
Maintainer: Xerra
License-Expression: BSD-3-Clause
Requires-Python: >=3.11
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM

# cft-jpegls

Maintained by **Xerra**, under the BSD-3-Clause license. Package name:
`cft-jpegls`; Python import: `cft_jpegls`.

Experimental **grayscale JPEG-LS** decoding in Rust, exposed through PyO3.
No private viewer or C++ runtime is needed. This is not a general RGB JPEG-LS
implementation and is not yet the default cft-zarr decoder.

```python
import cft_jpegls

pixels = cft_jpegls.decode(jpegls_bytes)  # raw uint16, shape (Y, X)
chunk = await cft_jpegls.decode_chunk_async(
    cft_chunk_bytes, (64, 256, 256), shift12=True
)
```

The default pool is created lazily and shared across calls/arrays. It uses all
logical CPUs available to the process (system CPU count on Python 3.11–3.12).
Each native worker decodes a complete chunk. There is no Python compute
executor or nested frame pool. Async calls yield to the event loop while Rayon
decodes. Sync calls release the GIL, but callers must use the async functions
inside an IO event loop. A single sync call does not parallelize one image.

`paired=True` opts into experimental two-frame interleaving on one worker.
Compatible adjacent 12-bit NEAR=1/2 frames use the paired kernel; other frames
use ordinary Rust. No CharLS fallback is included. Mac benchmarks favored pairs;
Windows benchmarks did not consistently do so. Default decoding is scalar.

## Supported data and errors

The decoder supports one non-interleaved grayscale scan, 2–16-bit precision,
lossless and near-lossless, full-range MAXVAL, custom LSE type 1 thresholds/reset,
and APP/COM segments. It rejects unsupported extensions, including RGB/multiple
components, restart intervals, mapping tables, DNL and SPIFF nesting.
`UnsupportedError` and `DecodeError` are ValueError subclasses. Malformed inputs
raise errors; partial output is discarded, never returned as a valid image.

Chunk input is a bare JPEG-LS stream or CFT framing: a big-endian u32 count,
followed by big-endian u32 length and payload for each frame. At most 65,536
frames are accepted. Empty frame payloads and trailing missing Z planes are
zero-filled. Frame geometry must fit the requested (Z,Y,X) shape. `shift12=True`
applies the unconditional uint16 four-bit left shift required by CFT.

Input must be immutable `bytes`. Encoded input is capped at 256 MiB. The default
`max_pixels=16_777_216` caps frame/chunk output at 32 MiB; callers can explicitly
increase it to at most 268,435,456 pixels. NumPy arrays take ownership of Rust's
output allocation without a second full pixel copy. The pool bounds active
workers, not queued inputs, aggregate output, or a viewer cache. Callers should
bound the number of outstanding submissions.

Cancellation skips work that has not started. A running native decode completes;
its private output cannot overwrite a caller's destination. No hard interruption
of a native decode is provided. Multiprocessing spawn is supported. Do not reuse
a native pool inherited after POSIX fork; it raises a RuntimeError instead of
waiting on vanished worker threads. Use spawn/forkserver or import and first use
this module only in the child. Subinterpreters/free-threaded operation are not
claimed as supported in this alpha.

## Build and test

```sh
python -m pip install maturin pytest imagecodecs numpy
maturin build --release
python -m pip install target/wheels/cft_jpegls-*.whl
pytest tests
```

Build wheels and source archives from this directory using maturin. The sdist
includes the pinned Rust decoder and its BSD license; no sibling checkout is
needed. See PROVENANCE.md. Test inputs are synthetic; no private imaging data
is distributed. Windows and macOS validation is recorded separately. Linux
build support must be validated before claiming Linux wheel coverage.

## Release

From a Python environment containing
`maturin` and `twine`, run `./publish.sh --build-only` to produce a release wheel
for the current platform and a self-contained source distribution in `dist/`.
Collect wheels for other platforms at the same version in that directory, then
run `./publish.sh` to validate and upload those artifacts to PyPI. Credentials
come from Twine's standard environment/keyring configuration; no token belongs
in the script. Releases use the `xerra` PyPI account, as with `cft-zarr`.

Windows x86-64 and macOS arm64 release wheels have been tested with Python 3.12.
They use Python's stable ABI with a Python 3.11 minimum. Linux and macOS x86-64
have build jobs defined, but are not yet locally validated.

