All formats

imagecodecs

LanguagePython 3 (Cython extension)
LicenseBSD-3-Clause (jxrlib: BSD-2-Clause)
Repositorygithub.com/cgohlke/imagecodecs
DocumentationREADME and docstrings
Depends onNumPy; jxrlib is built into the wheels
Read / writeyes / yes; gray, RGB, RGBA, CMYK; uint8, uint16, float16, float32 and fixed-point samples

imagecodecs is a set of image codecs for NumPy arrays, used by tifffile, zarr and napari. Its JPEG XR codec wraps jxrlib: jpegxr_decode returns an array with shape (height, width) or (height, width, samples), and jpegxr_encode turns an array into JPEG XR bytes. Half-float images, such as Windows HDR screenshots, decode to float16 arrays with values above 1.0 for bright areas.

It doesn’t read JPEG XR metadata (ICC profile, XMP, Exif) and has no region or reduced-resolution decoding.

Installation#

Shell
pip install imagecodecs

Binary wheels for Windows, macOS and Linux include jxrlib. Check with imagecodecs.JPEGXR.available (True).

Basic usage: decode and encode#

Python
import imagecodecs

with open("in.jxr", "rb") as f:
    data = f.read()

if imagecodecs.jpegxr_check(data):
    image = imagecodecs.jpegxr_decode(data)
    print(image.shape, image.dtype)        # e.g. (1440, 2560, 4) float16

    encoded = imagecodecs.jpegxr_encode(image)          # default level 1.0: lossless
    with open("copy.jxr", "wb") as f:
        f.write(encoded)

imagecodecs.imread("in.jxr") does the same in one call; it picks the codec from the .jxr, .hdp or .wdp extension.

How to convert a Windows HDR screenshot to PNG#

HDR screenshots are linear scRGB (1.0 = 80 nits, i.e. SDR white). This applies a simple tone map and the sRGB transfer curve, then saves an 8-bit PNG:

Python
import imagecodecs
import numpy as np

hdr = imagecodecs.imread("screenshot.jxr").astype(np.float32)   # (h, w, 4), linear scRGB
rgb = np.clip(hdr[..., :3], 0, None)
rgb = rgb / (1.0 + rgb)                          # Reinhard tone map: HDR -> 0..1
srgb = np.where(rgb <= 0.0031308, 12.92 * rgb, 1.055 * np.power(rgb, 1 / 2.4) - 0.055)
png = (np.clip(srgb, 0, 1) * 255 + 0.5).astype(np.uint8)
imagecodecs.imwrite("screenshot.png", png)
print("peak:", hdr[..., :3].max() * 80, "nits")

How to encode lossy JPEG XR#

level is the quality from 0.0 to 1.0; 1.0 is lossless:

Python
import imagecodecs
import numpy as np

image = imagecodecs.imread("in.png")             # uint8 RGB or RGBA
encoded = imagecodecs.jpegxr_encode(image, level=0.8, resolution=(96.0, 96.0))
with open("out.jxr", "wb") as f:
    f.write(encoded)

hdr = np.random.rand(256, 256, 3).astype(np.float32) * 4   # float32 HDR data
imagecodecs.imwrite("hdr.jxr", hdr, level=0.9)

Use hasalpha=True when the last channel of a 4-channel array is alpha, and photometric to choose between gray, RGB and CMYK interpretations.

How to get fixed-point images as integers#

Some JPEG XR files store fixed-point samples. By default they decode to float32; pass fp2int=True to get the raw int16 / int32 values:

Python
raw = imagecodecs.jpegxr_decode(data, fp2int=True)

Tips#