Python binding for the LittleCMS2 color management library.
pip install python-lcms2
Pre-built wheels are available on PyPI for Windows (x86-64, ARM64), Linux (x86-64, ARM64), and macOS (Intel, Apple Silicon) on Python 3.10 and later. Windows ARM64 requires Python 3.11 or later. For other platforms, see Building from source.
import lcms2A Profile can be created from a built-in name, a file on disk, or raw bytes in memory:
srgb = lcms2.Profile("sRGB")
prophoto = lcms2.Profile("ProPhoto RGB")
from_file = lcms2.Profile(filename="CMYK.icm")
with open("CMYK.icm", "rb") as f:
from_bytes = lcms2.Profile(buffer=f.read())Built-in profiles provided by LittleCMS: sRGB, Lab, XYZ.
Additional built-in RGB profiles: Adobe RGB (1998), Apple RGB, Best RGB, Beta RGB, Bruce RGB, CIE RGB, ColorMatch RGB, Don RGB 4, ECI RGB v2, Ekta Space PS5, NTSC RGB, PAL/SECAM RGB, ProPhoto RGB, SMPTE-C RGB, _sRGB, Wide Gamut RGB.
A Transform converts pixel data from one profile and format to another:
lab = lcms2.Profile("Lab")
srgb = lcms2.Profile("sRGB")
transform = lcms2.Transform(lab, "Lab_DBL", srgb, "RGB_16")The constructor signature is:
Transform(src_profile, src_format, dst_profile, dst_format, intent="PERCEPTUAL", flags="NONE")
Format strings follow the pattern {COLORSPACE}_{DTYPE} with an optional suffix. The dtype suffix determines the NumPy array type expected at runtime:
| Suffix | NumPy dtype | Typical use |
|---|---|---|
_8 |
uint8 |
8-bit images (0–255) |
_16 |
uint16 |
16-bit images (0–65535) |
_FLT |
float32 |
Single-precision float |
_DBL |
float64 |
Double-precision float |
_HALF_FLT |
float16 |
Half-precision float |
Common colorspace prefixes: RGB, BGR, RGBA, BGRA, GRAY, Lab, XYZ, CMYK, YCbCr, HSV, HLS.
Optional suffixes: _PLANAR (channel-first layout), _REV (ink-reversed), _SE (swap-endian), _PREMUL (premultiplied alpha).
The full list of supported format strings:
lcms2.DATA_TYPES.keys()Rendering intents (lcms2.INTENT): PERCEPTUAL, RELATIVE_COLORIMETRIC, SATURATION, ABSOLUTE_COLORIMETRIC.
Flags (lcms2.FLAG) can be combined with commas, spaces, semicolons, or |:
transform = lcms2.Transform(lab, "Lab_DBL", srgb, "RGB_16",
intent="PERCEPTUAL",
flags="GAMUTCHECK,SOFTPROOFING")Transform.apply accepts a NumPy array or any array-compatible object and returns a transformed NumPy array. It works on single pixels, batches, and full images — the last dimension is always the channel axis:
result = transform.apply([50.0, 0.0, 0.0]) # L*a*b* neutral grey, shape (3,)The array dtype must match the source format declared at construction time. When passing lists or other convertibles, the data is cast automatically where possible.
apply treats any array shape as (..., channels), so a 2D image (H, W, C) is processed in one call:
import numpy as np
import lcms2
srgb = lcms2.Profile("sRGB")
prophoto = lcms2.Profile("ProPhoto RGB")
transform = lcms2.Transform(srgb, "RGB_8", prophoto, "RGB_16")
image = np.random.randint(0, 256, (480, 640, 3), dtype=np.uint8)
result = transform.apply(image) # shape (480, 640, 3), dtype uint16A common use case is editing in Lab — perceptually uniform, so lightness adjustments look natural. OpenCV loads images as BGR uint8:
import cv2
import numpy as np
import lcms2
import matplotlib.pyplot as plt
image = cv2.imread("photo.jpg") # uint8, BGR
srgb = lcms2.Profile("sRGB")
lab = lcms2.Profile("Lab")
to_lab = lcms2.Transform(srgb, "bgr_8", lab, "lab_flt")
to_srgb = lcms2.Transform(lab, "lab_flt", srgb, "rgb_flt")
lab_image = to_lab.apply(image)
lab_image[..., 0] = np.clip(lab_image[..., 0] * 1.2, 0, 100) # boost lightness
result = np.clip(to_srgb.apply(lab_image), 0.0, 1.0) # float32, RGB, 0.0–1.0
plt.imshow(result)
plt.show()Format strings are case-insensitive, so "BGR_8", "bgr_8", and "Bgr_8" are all accepted.
To save back to a file with cv2:
bgr_out = cv2.cvtColor((result * 255).astype(np.uint8), cv2.COLOR_RGB2BGR)
cv2.imwrite("output.jpg", bgr_out)Clone the repository with its submodules:
git clone --recurse-submodules https://github.com/wzjoriv/python-lcms2.git
cd python-lcms2
Install the build tool if needed:
pip install build --upgrade
Build a wheel:
python -m build --wheel
The wheel is written to dist/. Install it with:
pip install dist/python_lcms2*.whl
Windows path detection (Windows SDK include and library directories) is handled automatically via the registry in setup.py. If the build fails on your Windows installation, the paths may need to be adjusted manually.
For bugs, questions, and feature requests use GitHub Issues.
This project is a continuation of work by prior maintainers. The lineage of the repository is: sk1-project → RomanKosobrodov → wzjoriv.