Skip to main content

Fastest Python bindings for zero-copy JPEG XL & JPEG encoding/decoding and lossless transcoding (static linked)

Project description

pyjpegxl

PyPI version Python versions CI Status License

Python bindings for **JPEG XL** and **JPEG** encoding/decoding, powered by [libjxl](https://github.com/libjxl/libjxl) and [libjpeg-turbo](https://libjpeg-turbo.org/). Both libraries are statically linked — no system dependencies required.

Features:

  • JPEG XL + JPEG: Full encode/decode/file I/O for both formats in one package.
  • Lossless Transcoding: Reversibly transcode JPEGs into 20% smaller JXLs, and losslessly reconstruct the exact original JPEG bit-for-bit.
  • NumPy Zero-Copy: Directly encode from and decode to numpy.ndarray without memory duplication.
  • True Concurrency: Releases the Python GIL during heavy encoding/decoding operations, enabling true multi-threading.
  • Async API: First-class async/await support via asyncio.to_thread.
  • Performance: Fastest-in-class multi-threaded encoding and decoding.

Installation

pip install pyjpegxl

(Note: Pre-built wheels are currently only available for select platforms. If a wheel is not available, pip will try to build it from source. You will need a Rust toolchain installed.)

Build from source

Requires Rust toolchain and uv:

git clone https://github.com/twn39/pyjpegxl && cd pyjpegxl
# Install dependencies and build extension in-place
uv sync

Quick Start

Basic Usage (Bytes API)

import pyjpegxl

# Decode
with open("image.jxl", "rb") as f:
    meta, pixels = pyjpegxl.decode(f.read())

print(f"{meta.width}x{meta.height}, channels={meta.num_channels}")

# Encode
jxl_data = pyjpegxl.encode(pixels, width=meta.width, height=meta.height)

# Custom Encode
jxl_data = pyjpegxl.encode(
    pixels, width=meta.width, height=meta.height,
    lossless=True,
    speed=pyjpegxl.EncoderSpeed.Falcon,
)

NumPy Zero-Copy API

Move raw bytes to and from NumPy arrays instantly without Python-level allocations.

import pyjpegxl
import numpy as np

with open("image.jxl", "rb") as f:
    # Decode directly into a NumPy array (H, W, C)
    meta, arr = pyjpegxl.decode_to_numpy(f.read())

print(arr.shape, arr.dtype) # e.g. (1080, 1920, 3), dtype('uint8')

# Encode directly from a C-contiguous NumPy array
jxl_data = pyjpegxl.encode_from_numpy(arr, quality=1.0) # quality=1.0 is default for visually lossless

File I/O API

Read and write JXL files directly — no manual open() needed.

import pyjpegxl

# Read a JXL file to a NumPy array
meta, arr = pyjpegxl.read_to_numpy("image.jxl")
print(arr.shape, arr.dtype)

# Write a NumPy array to a JXL file
pyjpegxl.write_from_numpy("output.jxl", arr, lossless=True)

# Bytes-level file I/O
meta, pixels = pyjpegxl.read("image.jxl")
pyjpegxl.write("output.jxl", pixels, width=meta.width, height=meta.height,
               num_channels=meta.num_color_channels + int(meta.has_alpha))

Async API

Perfect for high-concurrency web servers like FastAPI or Starlette.

import asyncio
import pyjpegxl

async def process_image():
    with open("image.jxl", "rb") as f:
        data = f.read()
        
    # Non-blocking decode
    meta, arr = await pyjpegxl.async_decode_to_numpy(data)
    
    # Non-blocking encode
    out_jxl = await pyjpegxl.async_encode_from_numpy(arr)
    
    return out_jxl

asyncio.run(process_image())

JPEG Quick Start

import pyjpegxl

# Read JPEG → NumPy array
info, arr = pyjpegxl.jpeg_read_to_numpy("photo.jpg")
print(arr.shape)  # (H, W, 3)

# Write NumPy array → JPEG file
pyjpegxl.jpeg_write_from_numpy("output.jpg", arr, quality=95)

# In-memory encode/decode
jpeg_data = pyjpegxl.jpeg_encode_from_numpy(arr, quality=90)
info, decoded = pyjpegxl.jpeg_decode_to_numpy(jpeg_data)

Direct JPEG ↔ JXL Lossless Transcoding

Repack JPEGs into smaller JXL files losslessly without ever decoding pixels, and revert them exactly bit-for-bit!

import pyjpegxl

with open("photo.jpg", "rb") as f:
    jpeg_bytes = f.read()

# Transcode directly (lossless, usually 20% smaller)
jxl_bytes = pyjpegxl.jpeg_to_jxl(jpeg_bytes)

# Reconstruct the exact original JPEG bit-for-bit
restored_jpeg_bytes = pyjpegxl.jxl_to_jpeg(jxl_bytes)
assert jpeg_bytes == restored_jpeg_bytes

# Also available natively for File I/O
pyjpegxl.jpeg_file_to_jxl("photo.jpg", "smaller_version.jxl")
pyjpegxl.jxl_file_to_jpeg("smaller_version.jxl", "restored_photo.jpg")

Concurrency and Performance

pyjpegxl natively releases the Global Interpreter Lock (GIL) and engages ThreadsRunner from libjxl. If you use concurrent.futures.ThreadPoolExecutor or asyncio.gather(), multiple images will encode and decode perfectly in parallel without blocking the main Python thread.

Benchmarks (MacBook M-Series)

Benchmark processing images/test.jpg (decoded to Numpy arrays) among Python JXL wrappers on identical visual quality settings:

Library Decode Time (ms) Peak Python Mem Encode Time (ms) Peak Python Mem
pyjpegxl 36.78 0.0 MB 184.47 0.4 MB
pylibjxl 114.86 0.0 MB 366.54 0.5 MB
pillow-jxl 35.56 11.9 MB 185.22 11.3 MB

pyjpegxl is fundamentally the fastest encoder and decoder, while matching the flawless memory performance of pylibjxl due to its zero-copy IntoPyArray bridging.

API Reference

JXL Bytes API

  • decode(data: bytes) -> tuple[Metadata, bytes]
  • encode(data, width, height, *, lossless=False, quality=1.0, speed=EncoderSpeed.Squirrel, num_channels=4) -> bytes

JXL NumPy API

  • decode_to_numpy(data: bytes) -> tuple[Metadata, np.ndarray]
  • encode_from_numpy(array: np.ndarray, *, lossless=False, quality=1.0, speed=EncoderSpeed.Squirrel) -> bytes

JXL File I/O API

  • read(path) -> tuple[Metadata, bytes]
  • read_to_numpy(path) -> tuple[Metadata, np.ndarray]
  • write(path, data, width, height, **kwargs) -> int
  • write_from_numpy(path, array, **kwargs) -> int

JPEG Bytes API

  • jpeg_decode(data: bytes) -> tuple[JpegInfo, bytes]
  • jpeg_encode(data, width, height, *, quality=95, num_channels=3) -> bytes

JPEG NumPy API

  • jpeg_decode_to_numpy(data: bytes) -> tuple[JpegInfo, np.ndarray]
  • jpeg_encode_from_numpy(array: np.ndarray, *, quality=95) -> bytes

JPEG File I/O API

  • jpeg_read(path) -> tuple[JpegInfo, bytes]
  • jpeg_read_to_numpy(path) -> tuple[JpegInfo, np.ndarray]
  • jpeg_write(path, data, width, height, **kwargs) -> int
  • jpeg_write_from_numpy(path, array, **kwargs) -> int

Transcoding API

  • jpeg_to_jxl(data: bytes) -> bytes
  • jxl_to_jpeg(data: bytes) -> bytes
  • jpeg_file_to_jxl(jpeg_path: str, jxl_path: str) -> int
  • jxl_file_to_jpeg(jxl_path: str, jpeg_path: str) -> int

Async API

All sync functions have async variants prefixed with async_ (JXL) or async_jpeg_ (JPEG).

Types

  • Metadata: JXL image dimensions and channel information.
  • JpegInfo: JPEG image dimensions and channel count.
  • EncoderSpeed: JXL compression effort (LightningTortoise).

License

BSD 3-Clause

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyjpegxl-0.2.1.tar.gz (5.5 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

pyjpegxl-0.2.1-cp314-cp314-win_amd64.whl (5.4 MB view details)

Uploaded CPython 3.14Windows x86-64

pyjpegxl-0.2.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.8 MB view details)

Uploaded CPython 3.14manylinux: glibc 2.17+ x86-64

pyjpegxl-0.2.1-cp314-cp314-macosx_14_0_x86_64.macosx_14_0_arm64.macosx_14_0_universal2.whl (4.7 MB view details)

Uploaded CPython 3.14macOS 14.0+ ARM64macOS 14.0+ universal2 (ARM64, x86-64)macOS 14.0+ x86-64

pyjpegxl-0.2.1-cp313-cp313-win_amd64.whl (5.4 MB view details)

Uploaded CPython 3.13Windows x86-64

pyjpegxl-0.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.8 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

pyjpegxl-0.2.1-cp313-cp313-macosx_14_0_x86_64.macosx_14_0_arm64.macosx_14_0_universal2.whl (4.7 MB view details)

Uploaded CPython 3.13macOS 14.0+ ARM64macOS 14.0+ universal2 (ARM64, x86-64)macOS 14.0+ x86-64

pyjpegxl-0.2.1-cp312-cp312-win_amd64.whl (5.4 MB view details)

Uploaded CPython 3.12Windows x86-64

pyjpegxl-0.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.8 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

pyjpegxl-0.2.1-cp312-cp312-macosx_14_0_x86_64.macosx_14_0_arm64.macosx_14_0_universal2.whl (4.7 MB view details)

Uploaded CPython 3.12macOS 14.0+ ARM64macOS 14.0+ universal2 (ARM64, x86-64)macOS 14.0+ x86-64

pyjpegxl-0.2.1-cp311-cp311-win_amd64.whl (5.4 MB view details)

Uploaded CPython 3.11Windows x86-64

pyjpegxl-0.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.8 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

pyjpegxl-0.2.1-cp311-cp311-macosx_14_0_x86_64.macosx_14_0_arm64.macosx_14_0_universal2.whl (4.7 MB view details)

Uploaded CPython 3.11macOS 14.0+ ARM64macOS 14.0+ universal2 (ARM64, x86-64)macOS 14.0+ x86-64

File details

Details for the file pyjpegxl-0.2.1.tar.gz.

File metadata

  • Download URL: pyjpegxl-0.2.1.tar.gz
  • Upload date:
  • Size: 5.5 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyjpegxl-0.2.1.tar.gz
Algorithm Hash digest
SHA256 c62e10fcb8b4bf62f7637390893471eeeb75ea5a02de26208e7eedcbe4ced9c1
MD5 ccb0345298368d25f30d9b2057892f6f
BLAKE2b-256 41b2b1a284deaba76fcbb2fe08727ac7452569440b041f1944bcddba9fe6e7b8

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyjpegxl-0.2.1.tar.gz:

Publisher: ci.yml on twn39/pyjpegxl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyjpegxl-0.2.1-cp314-cp314-win_amd64.whl.

File metadata

  • Download URL: pyjpegxl-0.2.1-cp314-cp314-win_amd64.whl
  • Upload date:
  • Size: 5.4 MB
  • Tags: CPython 3.14, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyjpegxl-0.2.1-cp314-cp314-win_amd64.whl
Algorithm Hash digest
SHA256 38eb3be4155961cf27de9ea48c6a14ac6335475b71f499bfa520579e072ce993
MD5 33873e1c1cd70562dc1fab98caa5a915
BLAKE2b-256 5fc2353d89609ef595561c9e17da5403cf6a0fcb92271395014efe31f34ecf00

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyjpegxl-0.2.1-cp314-cp314-win_amd64.whl:

Publisher: ci.yml on twn39/pyjpegxl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyjpegxl-0.2.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyjpegxl-0.2.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 ac3147f374fef889516195e1ea3e0f0ca66bc61431f3bdffd059cc053b9f8d55
MD5 fb601babdb11de26caf0f6054390d7c3
BLAKE2b-256 4b3436ef2bd6775768a80827f365e8d7dd13f2e3c5a9c9d0e8e6f8be9ac8e585

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyjpegxl-0.2.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: ci.yml on twn39/pyjpegxl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyjpegxl-0.2.1-cp314-cp314-macosx_14_0_x86_64.macosx_14_0_arm64.macosx_14_0_universal2.whl.

File metadata

File hashes

Hashes for pyjpegxl-0.2.1-cp314-cp314-macosx_14_0_x86_64.macosx_14_0_arm64.macosx_14_0_universal2.whl
Algorithm Hash digest
SHA256 d2de22a2ce39e90fe2d5317c7e2693c7daf6905d0fa76e586de80557fb76c205
MD5 5c7a2d1b2174563ef9744fc41348e713
BLAKE2b-256 41bfaf3c4cc47d37e7f45e61fd7b395166b12109812428f545c3184a757110e5

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyjpegxl-0.2.1-cp314-cp314-macosx_14_0_x86_64.macosx_14_0_arm64.macosx_14_0_universal2.whl:

Publisher: ci.yml on twn39/pyjpegxl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyjpegxl-0.2.1-cp313-cp313-win_amd64.whl.

File metadata

  • Download URL: pyjpegxl-0.2.1-cp313-cp313-win_amd64.whl
  • Upload date:
  • Size: 5.4 MB
  • Tags: CPython 3.13, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyjpegxl-0.2.1-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 e51bc4a0d6c2a0b0a64f3457884cf55acbc25533f5ce0999b8815dd96ba4291c
MD5 24f9ee27bdb99261a8b494410b1a99ab
BLAKE2b-256 58f7289130b637ba3b966cd6ca01d6b656d3f29be97e125c3853dd186b7902ed

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyjpegxl-0.2.1-cp313-cp313-win_amd64.whl:

Publisher: ci.yml on twn39/pyjpegxl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyjpegxl-0.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyjpegxl-0.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 acf4657fced57ef74a729cd12732ea07825b0cc2ef512a152b4203930dac126a
MD5 29561d280b2202bd0846091275d538ec
BLAKE2b-256 7aaaa982d16e82ffb3c94c4fad69b68a813d7a75f01e4d620c94aa82d269a95e

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyjpegxl-0.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: ci.yml on twn39/pyjpegxl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyjpegxl-0.2.1-cp313-cp313-macosx_14_0_x86_64.macosx_14_0_arm64.macosx_14_0_universal2.whl.

File metadata

File hashes

Hashes for pyjpegxl-0.2.1-cp313-cp313-macosx_14_0_x86_64.macosx_14_0_arm64.macosx_14_0_universal2.whl
Algorithm Hash digest
SHA256 4c9846d943e4940b6e1570616e5ea36e37565154643cec18f1e58e0b7f949606
MD5 a688912d71b24bebf58268a3f771fa6e
BLAKE2b-256 fd206f1e87fab792cf63ec4c11c2b895a225758a641fcb30240fc58a8b478a2b

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyjpegxl-0.2.1-cp313-cp313-macosx_14_0_x86_64.macosx_14_0_arm64.macosx_14_0_universal2.whl:

Publisher: ci.yml on twn39/pyjpegxl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyjpegxl-0.2.1-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: pyjpegxl-0.2.1-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 5.4 MB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyjpegxl-0.2.1-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 4706526b354f890761468c881920b53035ff558c532c790990adcbebf64bc36a
MD5 b9a191e1705fb73ce11e5e20447d1f71
BLAKE2b-256 cfff86a8662d5e9f2a812fe2b88c22c3735deae0bfbf359e889190f887543f7c

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyjpegxl-0.2.1-cp312-cp312-win_amd64.whl:

Publisher: ci.yml on twn39/pyjpegxl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyjpegxl-0.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyjpegxl-0.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 908793dbb742fcf411b658253ad52aefe6cecf7096498503641d7d7f39f8e3ab
MD5 49b17557bb535fb761f3aadf8db517fb
BLAKE2b-256 f307ca16bc4c0640cf22920e44a1b618b71a9c5813cec82f9b6328de6ff6adeb

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyjpegxl-0.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: ci.yml on twn39/pyjpegxl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyjpegxl-0.2.1-cp312-cp312-macosx_14_0_x86_64.macosx_14_0_arm64.macosx_14_0_universal2.whl.

File metadata

File hashes

Hashes for pyjpegxl-0.2.1-cp312-cp312-macosx_14_0_x86_64.macosx_14_0_arm64.macosx_14_0_universal2.whl
Algorithm Hash digest
SHA256 e321905a538170509ef1a8ddf6e2150ff9688643cc35d989990f9438213beee1
MD5 f9ca859326b0005896ae5bf955a2a72b
BLAKE2b-256 cf245a7099696d6e492d8af7803e23c5005baf49bf71fa815d77fe670c9788fd

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyjpegxl-0.2.1-cp312-cp312-macosx_14_0_x86_64.macosx_14_0_arm64.macosx_14_0_universal2.whl:

Publisher: ci.yml on twn39/pyjpegxl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyjpegxl-0.2.1-cp311-cp311-win_amd64.whl.

File metadata

  • Download URL: pyjpegxl-0.2.1-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 5.4 MB
  • Tags: CPython 3.11, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyjpegxl-0.2.1-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 206e7b7eebb53276047039433d709a887c09166b9215d8645b0089a4b3d49079
MD5 aed389fb522542de5595caea88fa8d27
BLAKE2b-256 1f158925f0d8b4ea7f5609c2a29b38b89bf7790243b4a88c8ee944e63cfcc73f

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyjpegxl-0.2.1-cp311-cp311-win_amd64.whl:

Publisher: ci.yml on twn39/pyjpegxl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyjpegxl-0.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyjpegxl-0.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 6f0c3eb9eeb2e51cbfcfb322f252ac7c9068d192207408aee63cd65776c77fee
MD5 b8e1ae277f5106395129b78f462937da
BLAKE2b-256 96e0b5526a32d97e7c53e51cf0186ff2aeeca316ec699d809759de6e8c358a14

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyjpegxl-0.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: ci.yml on twn39/pyjpegxl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyjpegxl-0.2.1-cp311-cp311-macosx_14_0_x86_64.macosx_14_0_arm64.macosx_14_0_universal2.whl.

File metadata

File hashes

Hashes for pyjpegxl-0.2.1-cp311-cp311-macosx_14_0_x86_64.macosx_14_0_arm64.macosx_14_0_universal2.whl
Algorithm Hash digest
SHA256 3057f654f807c89543161bb3c1cc9aebb1b66ec9c8bbf05406d0a9a5a102eb43
MD5 b8cca7b0e5c405cdc35f5d67b40f36d1
BLAKE2b-256 bd65e77704c540bbba41f632eed1198f094467fc9909fcc2590aa6a42b64e262

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyjpegxl-0.2.1-cp311-cp311-macosx_14_0_x86_64.macosx_14_0_arm64.macosx_14_0_universal2.whl:

Publisher: ci.yml on twn39/pyjpegxl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page