Project
Workspace, building and status
A Cargo workspace of five libraries and two programs, plus Python bindings built separately, MIT or Apache-2.0.
01Workspace
Package names are z-stackr-*; inside the code the crates are
called stacker_core, stacker_pipeline and so on.
| Package | What it holds |
|---|---|
z-stackr-cli | The command-line tool (binary z-stackr). |
z-stackr-gui | The desktop app, built with Slint (binary z-stackr-gui). |
z-stackr-core | The planar image type, linear/sRGB conversion, the settings schema and the file-backed tile store. |
z-stackr-align | The alignment engine: the refiners (Lucas-Kanade and Nelder-Mead), the warps, brightness correction, the coverage mask and the optional AKAZE + RANSAC seed. |
z-stackr-algo | The fusion algorithms (Apex, Relief with the guided filter and the multigrid solver, Strata), auto-cull and ordering, and the retouch session. |
z-stackr-pipeline | The stages both apps call: frame discovery and order, decoding, alignment, auto-cull, fusion, tiling and the out-of-core tile runner, encoding, the settings loader, and the choice of CPU or GPU. |
z-stackr-gpu | The GPU kernels through wgpu, kept out of the CPU crates. |
z-stackr-web | The browser version: the desktop app's window drawn on a canvas, built with Trunk. |
z-stackr-web-worker | The Web Worker that runs the pipeline in the browser, so the page stays responsive. |
z-stackr-web-core | The messages between the page and the worker, and the browser's memory budget. |
z-stackr-python | Python bindings (import name zstackr): stack_files and batch_stack for files, out of core, and stack_arrays for numpy arrays in memory. A thin layer over the crates above, built with maturin and kept outside the workspace so that cargo test --workspace never links Python. |
Every step both apps need exists exactly once, in z-stackr-pipeline:
one mode table for alignment, one decoder, one frame order, one encoder and
one settings loader. The desktop app and the command-line tool therefore give
the same pixels for the same frames and settings.
02Building
z-stackr needs a nightly Rust compiler, because it uses portable
SIMD (std::simd). The repository's
rust-toolchain.toml pins the exact nightly with Clippy and rustfmt;
rustup toolchain install in the checkout installs it. Programs are
written to target/release/.
| Feature | Adds | Default |
|---|---|---|
akaze | Seeding the alignment from AKAZE feature matches | on in the desktop app, off in the command line |
gpu | Alignment, Apex, Relief, Strata and the multigrid solver on the GPU through wgpu (GPU) | off |
raw | Camera RAW files (CR2, CR3, NEF, ARW, DNG, RAF, ORF, RW2, PEF and others) as input frames; native only | off |
cargo build --release -p z-stackr-gui
cargo build --release -p z-stackr-cli --features akaze
cargo build --release -p z-stackr-gui --features gpu
cargo build --release -p z-stackr-cli --features raw
The Python bindings are built from their own folder with
maturin develop --release (or maturin build --release
for a wheel); the gpu, raw and akaze
features are passed with --features.
CPU level
The SIMD width is fixed when the program is compiled: 16 lanes with AVX-512, 8 with AVX2, otherwise 4. A plain build targets baseline x86-64 (SSE2, 4 lanes) and runs everywhere; the output is the same at every width, only the speed changes. For any processor with AVX2 and FMA (Intel Haswell, AMD Zen and newer):
RUSTFLAGS="-C target-cpu=x86-64-v3" cargo build --release -p z-stackr-gui
$env:RUSTFLAGS = "-C target-cpu=x86-64-v3"; cargo build --release -p z-stackr-gui
-C target-cpu=native also enables AVX-512 where the processor has
it, but the program then runs only on processors with the same features.
03Testing
Unit, integration and end-to-end tests cover every package; the end-to-end
tests stack the sample frames in the repository. The desktop app is tested
headless: a harness drives the real window with clicks and key presses and
runs every button, shortcut and menu item in every app state. A second harness,
slint-harness, runs the
window in a throw-away profile: it checks the layout at the default and the
smallest window size, clicks every control, stacks with each engine, and
fails when a control in the interface files is reached by no scenario. The GPU kernels
are checked against the CPU code and with injected device failures; on a
machine without a GPU adapter those tests report SKIPPED.
cargo test -p z-stackr-pipeline
cargo test -p z-stackr-gui --lib ui_flows
cargo test -p z-stackr-gui --features ui-harness --test ui
04Status and limits
- There are no ready-built programs yet; build from source, or use the browser version.
- No color profile is applied when frames are read, and alpha is dropped.
copy_metadatacopies the first frame's EXIF block into PNG and JPEG results; a TIFF cannot carry it.- Strata and the multigrid solver have kernels for the GPU in the native builds; Strata in the command-line tool runs on the CPU. Their timings have not been measured yet.
- The desktop app holds the whole stack in memory by default (12 bytes per pixel and frame, plus about 84 per pixel for Apex, 62 for Relief and 150 for Strata). Set a tile size in its settings, or use the command-line tool, for stacks that do not fit.
- The Python bindings run Apex, Relief and Strata; build them from source with maturin.
- GPU results agree with the CPU within a small tolerance, not bit for bit (see GPU).
05Licence
z-stackr is licensed under either the Apache License, Version 2.0, or the MIT
licence, at your option. Every package declares
license = "MIT OR Apache-2.0". Contributions, bug reports and
feature requests are welcome.