Python bindings for a fast RLE decoder/encoder, with a focus on use as a plugin for pylibjpeg
Project Links
Meta
Author: pylibjpeg-rle contributors
Requires Python: >=3.10
Classifiers
License
- OSI Approved :: MIT License
Intended Audience
- Developers
- Healthcare Industry
- Science/Research
Development Status
- 5 - Production/Stable
Natural Language
- English
Programming Language
- Rust
- Python :: 3.10
- Python :: 3.11
- Python :: 3.12
- Python :: 3.13
- Python :: 3.14
Operating System
- MacOS :: MacOS X
- POSIX :: Linux
- Microsoft :: Windows
Topic
- Scientific/Engineering :: Medical Science Apps.
- Software Development :: Libraries
pylibjpeg-rle
A fast DICOM (PackBits) RLE plugin for pylibjpeg, written in Rust with a Python wrapper.
Linux, MacOS and Windows are all supported.
Installation
Installing the current release
pip install pylibjpeg-rle
Installing the development version
Make sure Python, Git and Rust are installed. For Windows, you also need to install Microsoft's C++ Build Tools.
git clone https://github.com/pydicom/pylibjpeg-rle
cd pylibjpeg-rle
python -m pip install .
Supported Transfer Syntaxes
| UID | Description | Decoding | Encoding |
|---|---|---|---|
| 1.2.840.10008.1.2.5 | RLE Lossless | Yes | Yes |
Usage
Decoding
With pylibjpeg
from pydicom import dcmread
from pydicom.data import get_testdata_file
ds = dcmread(get_testdata_file("OBXXXX1A_rle.dcm"))
arr = ds.pixel_array
Standalone with pydicom
Alternatively you can use the included functions to decode a given dataset:
from rle import pixel_array, generate_frames
# Return the entire Pixel Data as an ndarray
arr = pixel_array(ds)
# Generator function that only processes 1 frame at a time,
# may help reduce memory usage when dealing with large Pixel Data
for arr in generate_frames(ds):
print(arr.shape)
Encoding
Standalone with pydicom
Convert uncompressed pixel data to RLE encoding and save:
from pydicom import dcmread
from pydicom.data import get_testdata_file
from pydicom.uid import RLELossless
from rle import pixel_data
# Get the uncompressed pixel data
ds = dcmread(get_testdata_file("OBXXXX1A.dcm"))
arr = ds.pixel_array
# RLE encode and encapsulate `arr`
ds.PixelData = pixel_data(arr, ds)
# Set the correct *Transfer Syntax UID*
ds.file_meta.TransferSyntaxUID = RLELossless
ds.save_as('as_rle.dcm')
Benchmarks
Decoding
Time per 1000 decodes, pydicom's default RLE decoder vs. pylibjpeg-rle:
| Dataset | Pixels | Bytes | pydicom | pylibjpeg-rle |
|---|---|---|---|---|
| OBXXXX1A_rle.dcm | 480,000 | 480,000 | 5.7 s | 1.1 s |
| OBXXXX1A_rle_2frame.dcm | 960,000 | 960,000 | 11.5 s | 2.1 s |
| SC_rgb_rle.dcm | 10,000 | 30,000 | 0.28 s | 0.19 s |
| SC_rgb_rle_2frame.dcm | 20,000 | 60,000 | 0.45 s | 0.28 s |
| MR_small_RLE.dcm | 4,096 | 8,192 | 0.46 s | 0.15 s |
| emri_small_RLE.dcm | 40,960 | 81,920 | 1.8 s | 0.67 s |
| SC_rgb_rle_16bit.dcm | 10,000 | 60,000 | 0.48 s | 0.25 s |
| SC_rgb_rle_16bit_2frame.dcm | 20,000 | 120,000 | 0.86 s | 0.39 s |
| rtdose_rle_1frame.dcm | 100 | 400 | 0.16 s | 0.13 s |
| rtdose_rle.dcm | 1,500 | 6,000 | 1.0 s | 0.64 s |
| SC_rgb_rle_32bit.dcm | 10,000 | 120,000 | 0.82 s | 0.35 s |
| SC_rgb_rle_32bit_2frame.dcm | 20,000 | 240,000 | 1.5 s | 0.60 s |
Encoding
Time per 1000 encodes, pydicom's default RLE encoder vs. pylibjpeg-rle and python-gdcm:
| Dataset | Pixels | Bytes | pydicom | pylibjpeg-rle | python-gdcm |
|---|---|---|---|---|---|
| OBXXXX1A.dcm | 480,000 | 480,000 | 30.6 s | 1.4 s | 1.5 s |
| SC_rgb.dcm | 10,000 | 30,000 | 1.9 s | 0.11 s | 0.21 s |
| MR_small.dcm | 4,096 | 8,192 | 3.0 s | 0.11 s | 0.29 s |
| SC_rgb_16bit.dcm | 10,000 | 60,000 | 3.6 s | 0.18 s | 0.28 s |
| rtdose_1frame.dcm | 100 | 400 | 0.28 s | 0.04 s | 0.14 s |
| SC_rgb_32bit.dcm | 10,000 | 120,000 | 7.1 s | 0.32 s | 0.43 s |
2.2.0
Sep 07, 2025
2.1.0
May 01, 2025
2.0.0
Jan 06, 2024
1.3.0
Jan 22, 2022
1.2.0
Jan 02, 2022
1.1.0
May 02, 2021
1.0.0
Apr 23, 2021
Wheel compatibility matrix
Files in release
pylibjpeg_rle-2.2.0-cp310-cp310-macosx_10_12_x86_64.whl (246.5KiB)
pylibjpeg_rle-2.2.0-cp310-cp310-macosx_11_0_arm64.whl (238.8KiB)
pylibjpeg_rle-2.2.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (266.7KiB)
pylibjpeg_rle-2.2.0-cp310-cp310-manylinux_2_28_aarch64.whl (264.5KiB)
pylibjpeg_rle-2.2.0-cp310-cp310-win32.whl (131.6KiB)
pylibjpeg_rle-2.2.0-cp310-cp310-win_amd64.whl (137.5KiB)
pylibjpeg_rle-2.2.0-cp311-cp311-macosx_10_12_x86_64.whl (246.2KiB)
pylibjpeg_rle-2.2.0-cp311-cp311-macosx_11_0_arm64.whl (238.6KiB)
pylibjpeg_rle-2.2.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (266.4KiB)
pylibjpeg_rle-2.2.0-cp311-cp311-manylinux_2_28_aarch64.whl (264.4KiB)
pylibjpeg_rle-2.2.0-cp311-cp311-win32.whl (131.4KiB)
pylibjpeg_rle-2.2.0-cp311-cp311-win_amd64.whl (137.4KiB)
pylibjpeg_rle-2.2.0-cp312-cp312-macosx_10_13_x86_64.whl (243.8KiB)
pylibjpeg_rle-2.2.0-cp312-cp312-macosx_11_0_arm64.whl (235.9KiB)
pylibjpeg_rle-2.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (265.9KiB)
pylibjpeg_rle-2.2.0-cp312-cp312-manylinux_2_28_aarch64.whl (263.9KiB)
pylibjpeg_rle-2.2.0-cp312-cp312-win32.whl (131.8KiB)
pylibjpeg_rle-2.2.0-cp312-cp312-win_amd64.whl (137.4KiB)
pylibjpeg_rle-2.2.0-cp313-cp313-macosx_10_13_x86_64.whl (244.0KiB)
pylibjpeg_rle-2.2.0-cp313-cp313-macosx_11_0_arm64.whl (236.1KiB)
pylibjpeg_rle-2.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (266.3KiB)
pylibjpeg_rle-2.2.0-cp313-cp313-manylinux_2_28_aarch64.whl (264.3KiB)
pylibjpeg_rle-2.2.0-cp313-cp313-win32.whl (132.0KiB)
pylibjpeg_rle-2.2.0-cp313-cp313-win_amd64.whl (137.6KiB)
pylibjpeg_rle-2.2.0-cp314-cp314-macosx_10_13_x86_64.whl (243.5KiB)
pylibjpeg_rle-2.2.0-cp314-cp314-macosx_11_0_arm64.whl (235.6KiB)
pylibjpeg_rle-2.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (266.1KiB)
pylibjpeg_rle-2.2.0-cp314-cp314-manylinux_2_28_aarch64.whl (264.2KiB)
pylibjpeg_rle-2.2.0-cp314-cp314-win32.whl (132.2KiB)
pylibjpeg_rle-2.2.0-cp314-cp314-win_amd64.whl (137.7KiB)
pylibjpeg_rle-2.2.0.tar.gz (28.4KiB)