imagecodecs
| Language | Python 3 (Cython extension) |
|---|---|
| License | BSD-3-Clause (jxrlib: BSD-2-Clause) |
| Repository | github.com/cgohlke/imagecodecs |
| Documentation | README and docstrings |
| Depends on | NumPy; jxrlib is built into the wheels |
| Read / write | yes / 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#
pip install imagecodecs
Binary wheels for Windows, macOS and Linux include jxrlib. Check with imagecodecs.JPEGXR.available (True).
Basic usage: decode and encode#
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:
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:
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:
raw = imagecodecs.jpegxr_decode(data, fp2int=True)
Tips#
imagecodecs.jpegxr_version()returns the jxrlib version.- For tile-based TIFF files with JPEG XR compression (some microscopy formats), tifffile decodes them through imagecodecs automatically.