Zero-dependency image processing primitives written in Zig and packaged for Python.
| Area | Highlights |
|---|---|
| Images | PNG/JPEG load/save, resize & warp, crop/letterbox, insert/extract, Gaussian/median filters, motion blur |
| Pixels & Arrays | Direct indexing/assignment, slice updates, zero-copy NumPy interop both directions |
| Colors | 12 color models (Rgb/Rgba, Hsl/Hsv, Lab/Lch, Xyz/Xyb, Oklab/Oklch, Lms, Ycbcr) with automatic conversion |
| Canvas & Fonts | Lines, arcs, splines, polygons, flood fills, bitmap font text rendering |
| Geometry | Rectangle algebra, convex hulls, similarity/affine/projective transforms |
| Terminal Output | SGR, Braille, Sixel, and Kitty renderers with automatic format negotiation |
| Numerics | Matrices with rich linear algebra, PCA, optimization (Hungarian assignment + MaxLIPO+TR global optimizer), running statistics |
| QR Codes | Encode text/bytes to QR images and decode them back, including from photos (perspective, uneven lighting, rotation) |
All functionality is implemented in Zig with no runtime dependencies, making the wheel lightweight and easy to vendor.
pip install zignal-processing- Python 3.10 – 3.14 (CPython)
- Prebuilt wheels ship for:
- Linux (manylinux2014)
x86_64,aarch64 - macOS
x86_64andarm64 - Windows
x86_64
- Linux (manylinux2014)
- Building from source requires Zig 0.15.0 or newer available on your
PATH.
If CPython headers/libraries are in a non-standard location, set PYTHON_INCLUDE_DIR, PYTHON_LIBS_DIR, and PYTHON_LIB_NAME before installing.
import numpy as np
import zignal
# Load or create an image
img = zignal.Image.load("photo.jpg") # PNG/JPEG
canvas = zignal.Image(480, 640, color=zignal.Rgb(30, 144, 255)).canvas()
# Draw & process
canvas.draw_circle((120, 160), 60, zignal.Rgba(255, 255, 255, 180), fill=True)
img = img.gaussian_blur(1.5)
img = img.resize(0.5, zignal.Interpolation.BILINEAR)
# Pixels + NumPy (shared memory views)
img[10, 20] = zignal.Hsv(60, 100, 100)
np_view = img.to_numpy() # (rows, cols, 3) uint8 view
np_view[..., 0] = np.clip(np_view[..., 0] + 32, 0, 255) # modifies img in-place
img2 = zignal.Image.from_numpy(np_view) # zero-copy back into Zig
# Streaming stats & procedural noise
stats = zignal.RunningStats()
for value in np_view.mean(axis=-1).flat:
stats.add(float(value))
noise = zignal.perlin(0.2, 0.4, amplitude=1.2, frequency=2.5, octaves=4)
print(f"μ={stats.mean:.3f} σ={stats.std_dev:.3f} perlin={noise:.3f}")
# Terminal preview (auto: kitty → iterm2 → sixel → sgr fallback)
print(f"{img:auto}")
# Save
img.save("out.png")- Docs: https://arrufat.github.io/zignal/python/zignal.html
- Source: https://github.com/arrufat/zignal
- Issues: https://github.com/arrufat/zignal/issues
zig build python-bindings # build extension + stubs
cd bindings/python
uv venv && uv pip install -e . # editable install
uv run pytest -q # run testsTo build a wheel for your current platform:
cd bindings/python
uv run python -m build --wheelTo cross-compile or specify optimization:
ZIG_TARGET=x86_64-linux-gnu ZIG_OPTIMIZE=ReleaseFast uv run python -m build --wheel| Variable | Description | Default |
|---|---|---|
ZIG_TARGET |
Zig target triple | native |
ZIG_OPTIMIZE |
Optimization mode (Debug, ReleaseSafe, ReleaseFast, ReleaseSmall) |
ReleaseFast |
ZIG_CPU |
CPU micro-architecture (e.g., baseline, x86_64_v3) |
baseline |
For portable Linux wheels, it is recommended to run auditwheel repair on the resulting wheel. On macOS, use delocate-wheel.
Follow the bindings guide for argument parsing helpers, enum registration, image ownership, and stub generation.
Special thanks to B Factory, Inc, the Founding Sponsor of Zignal. They originally developed this library and graciously transferred ownership to the community to ensure its long-term maintenance and growth.
MIT