image-rs
Work in progress: this project is not feature complete yet. The API may still change between releases.
Not affiliated with the image-rs organization on GitHub. This is a third party wrapper that makes the awesome Rust image crate available in the Python ecosystem.
image-rs is a thin wrapper around the image crate. It decodes images straight into NumPy arrays and encodes NumPy arrays back into image bytes.
Installation
pip install image-rs
or with uv:
uv add image-rs # add it as a dependency to your project
uv pip install image-rs # or install it into the current environment
The package requires Python 3.12 or newer and depends on NumPy.
Prebuilt wheels are only available for Linux x86_64 (manylinux2014, CPython 3.12–3.15). On every other platform pip builds the package from the source distribution, which requires a Rust toolchain in version 1.85 or newer (the crate uses the Rust 2024 edition).
Usage
from pathlib import Path
import image_rs
# Decode a JPEG into a (height, width, 3) uint8 NumPy array.
image = image_rs.decode_uint8_image(
Path("image.jpg").read_bytes(), image_rs.ImageFormat.JPEG, num_channels=3
)
print(image.shape, image.dtype)
# Encode it again as JPEG ...
jpeg_bytes = image_rs.encode_uint8_image(image, image_rs.EncodingOptions.Jpeg(quality=90))
# ... or as PNG with the fastest compression settings.
png_bytes = image_rs.encode_uint8_image(
image,
image_rs.EncodingOptions.Png(
compression=image_rs.PngCompression.FAST,
filter=image_rs.PngFilter.NO_FILTER,
),
)
Path("image.png").write_bytes(png_bytes)
Besides decode_uint8_image there are decode_uint16_image and decode_float32_image (values between 0 and 1) for
PNG images, and encode_uint16_image for 16 bit PNG encoding. The encoding functions release the GIL while they run.
For the full interface with docstrings see the type stub
image_rs.pyi, which also ships with the package so
type checkers and IDEs pick it up. More examples live in the
examples directory.
Currently supported functionality
- Image decoding
- PNG (uint8, uint16, float32)
- JPEG (uint8)
- All other formats supported by the image crate
- Image encoding
- PNG (uint8, uint16)
- JPEG (uint8)
- All other formats supported by the image crate
Benchmark results
To run the benchmark scripts yourself, run
steward sync --include-examples after the development setup to get the needed dependencies.
The presented results were measured on a PC with an AMD 9800x3d, using a build with the dist profile like the
wheels created by steward build. They were recorded with an earlier release on Python 3.10, before the minimum
supported version was raised to 3.12, so treat them as a rough comparison rather than exact numbers.
Decoding (benchmark.py)
3 channel uint8 JPEG decoding
--------------------------------------------------------------------------------
image_rs: time_per_pass=0.037s, total_time=3.656s, num_passes=100
OpenCV: time_per_pass=0.034s, total_time=3.440s, num_passes=100
torchvision: time_per_pass=0.031s, total_time=3.076s, num_passes=100
pywuffs: time_per_pass=0.059s, total_time=5.947s, num_passes=100
Pillow: time_per_pass=0.052s, total_time=5.165s, num_passes=100
3 channel uint8 PNG decoding
--------------------------------------------------------------------------------
image_rs: time_per_pass=0.056s, total_time=5.631s, num_passes=100
OpenCV: time_per_pass=0.096s, total_time=9.577s, num_passes=100
torchvision: time_per_pass=0.128s, total_time=12.760s, num_passes=100
pywuffs: time_per_pass=0.094s, total_time=9.424s, num_passes=100
Pillow: time_per_pass=0.113s, total_time=11.290s, num_passes=100
3 channel uint16 PNG decoding
--------------------------------------------------------------------------------
image_rs: time_per_pass=0.090s, total_time=8.975s, num_passes=100
OpenCV: time_per_pass=0.172s, total_time=17.218s, num_passes=100
torchvision: time_per_pass=0.212s, total_time=21.189s, num_passes=100
Encoding (encoding_benchmark.py)
3 channel uint8 JPEG encoding (quality 90)
--------------------------------------------------------------------------------
image_rs: time_per_pass=0.177s, total_time=0.887s, num_passes=5, encoded_size=3660KiB
OpenCV: time_per_pass=0.022s, total_time=0.109s, num_passes=5, encoded_size=3427KiB
torchvision: time_per_pass=0.022s, total_time=0.108s, num_passes=5, encoded_size=3433KiB
Pillow: time_per_pass=0.027s, total_time=0.135s, num_passes=5, encoded_size=3433KiB
3 channel uint8 PNG encoding (balanced compression, zlib level 6)
--------------------------------------------------------------------------------
image_rs: time_per_pass=0.572s, total_time=2.858s, num_passes=5, encoded_size=15505KiB
OpenCV: time_per_pass=0.724s, total_time=3.621s, num_passes=5, encoded_size=15507KiB
torchvision: time_per_pass=2.129s, total_time=10.646s, num_passes=5, encoded_size=16266KiB
Pillow: time_per_pass=0.786s, total_time=3.931s, num_passes=5, encoded_size=15442KiB
3 channel uint8 PNG encoding (fastest compression, image_rs FAST vs. zlib level 1)
--------------------------------------------------------------------------------
image_rs: time_per_pass=0.053s, total_time=0.263s, num_passes=5, encoded_size=21709KiB
OpenCV: time_per_pass=0.282s, total_time=1.408s, num_passes=5, encoded_size=22495KiB
torchvision: time_per_pass=0.443s, total_time=2.216s, num_passes=5, encoded_size=16411KiB
Pillow: time_per_pass=0.346s, total_time=1.731s, num_passes=5, encoded_size=22354KiB
3 channel uint8 PNG encoding (fastest compression, image_rs FAST and no filter vs. zlib level 1)
--------------------------------------------------------------------------------
image_rs: time_per_pass=0.042s, total_time=0.210s, num_passes=5, encoded_size=36726KiB
OpenCV: time_per_pass=0.282s, total_time=1.408s, num_passes=5, encoded_size=22495KiB
3 channel uint16 PNG encoding (balanced compression, zlib level 6)
--------------------------------------------------------------------------------
image_rs: time_per_pass=1.433s, total_time=7.167s, num_passes=5, encoded_size=17304KiB
OpenCV: time_per_pass=1.692s, total_time=8.458s, num_passes=5, encoded_size=17327KiB
3 channel uint16 PNG encoding (fastest compression, image_rs FAST vs. zlib level 1)
--------------------------------------------------------------------------------
image_rs: time_per_pass=0.117s, total_time=0.586s, num_passes=5, encoded_size=42940KiB
OpenCV: time_per_pass=0.445s, total_time=2.225s, num_passes=5, encoded_size=31323KiB
3 channel uint16 PNG encoding (fastest compression, image_rs FAST and no filter vs. zlib level 1)
--------------------------------------------------------------------------------
image_rs: time_per_pass=0.098s, total_time=0.490s, num_passes=5, encoded_size=73449KiB
OpenCV: time_per_pass=0.443s, total_time=2.216s, num_passes=5, encoded_size=31323KiB
Development setup
The project depends on the following tools that need to be present in the development environment: git, cargo,
rustc, rustfmt, clippy, docker and uv.
Everything else will be installed with a ./steward.py sync. After this first sync call the steward command is also
everywhere available in the venv.
Other notable steward commands:
steward build local: good for a quick local build of wheels. The wheels are bound to the glibc version of the local system, so usesteward build dockerfor wheels that should run on other machines.steward build docker: by default builds wheels for all currently supported python targets in a manylinux2014 environment.steward lint: runs autoformatting and linting for the whole project.steward prepare-publish: removesdist/, builds all wheels and the sdist withsteward build dockerand checks them withtwine check. The result indist/is ready for the upload to PyPI.
The tests run with uv run pytest. The project is installed in editable mode, and uv run rebuilds the Rust
extension first whenever a file in src/ changed.
Metadata
Release files for image-rs 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| image_rs-0.2.1.tar.gz | 13.4 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| image_rs-0.2.1-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.whl | CPython 3.15 | CPython 3.15 | Linux glibc 2.17+ x86-64 | Details |
| image_rs-0.2.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl | CPython 3.14 | CPython 3.14 | Linux glibc 2.17+ x86-64 | Details |
| image_rs-0.2.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl | CPython 3.13 | CPython 3.13 | Linux glibc 2.17+ x86-64 | Details |
| image_rs-0.2.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl | CPython 3.12 | CPython 3.12 | Linux glibc 2.17+ x86-64 | Details |
Total release size: 2.2 MB
Release files / image_rs-0.2.1.tar.gz
| Download URL | image_rs-0.2.1.tar.gz |
|---|---|
| Size | 13.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ab5c01d9d20979c9c91762c571e8b07d67f3ad17bf39197be522bf2f9cbd552b
|
|
BLAKE2b-256 checksum How to use checksums |
815656ad5eae7c35c18cdc67c57da9293189dfdcb3947efc19f706cb1ff03e28
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / image_rs-0.2.1-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
| Download URL | image_rs-0.2.1-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.whl |
|---|---|
| Size | 549.4 kB |
| Tags | CPython 3.15 Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
83ecd0dc98c4c9647223d7d724436374e4d9a2883c4ef95c3edc523c9ec73c78
|
|
BLAKE2b-256 checksum How to use checksums |
d8157407844d203d74dcc678fad59e000f07ed3a55e67f9632613fa070fe36b7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / image_rs-0.2.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
| Download URL | image_rs-0.2.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl |
|---|---|
| Size | 549.6 kB |
| Tags | CPython 3.14 Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
e785850c64219fb40dd177e75e32c68dd20d586bac9a74f129a30fb04509adc5
|
|
BLAKE2b-256 checksum How to use checksums |
aa14a9eeb761324bcfaabbad40a2e276c5cb75541dc7305c012069fcbb41477c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / image_rs-0.2.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
| Download URL | image_rs-0.2.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl |
|---|---|
| Size | 549.7 kB |
| Tags | CPython 3.13 Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
067be7325e610e28427cf398dd6a864c52867d9ea1716f0a7613a7e8783720f3
|
|
BLAKE2b-256 checksum How to use checksums |
cf57427be1199457728e4b74db87a3b44f0ab92cfeb71979a5f85436e39f14cf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / image_rs-0.2.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
| Download URL | image_rs-0.2.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl |
|---|---|
| Size | 549.5 kB |
| Tags | CPython 3.12 Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
bb63e240b87b08eed7290720ff56a90363caea8019ebf4b9cad0317802ff5a9d
|
|
BLAKE2b-256 checksum How to use checksums |
ad4a1d289e749af0ded3c51333352392e6e2b674411021031f74199bbf8985c6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|