Metadata-Version: 2.4
Name: python-lcms2
Version: 0.1.1
Summary: Python binding for LittleCMS2 library
Author-email: Josue N Rivera <josuevaldez1.com@gmail.com>
Project-URL: Homepage, https://github.com/wzjoriv/python-lcms2
Project-URL: Bug Tracker, https://github.com/wzjoriv/python-lcms2/issues
Keywords: color management,lcms2,icc,color profile,colorspace
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: C
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
Classifier: Operating System :: OS Independent
Classifier: Development Status :: 4 - Beta
Classifier: Topic :: Multimedia :: Graphics :: Graphics Conversion
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=2.0
Dynamic: license-file

# python-lcms2

Python binding for the [LittleCMS2](https://github.com/mm2/Little-CMS) color management library.

## Installation

```
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](#building-from-source).

## Usage

```python
import lcms2
```

### Profiles

A `Profile` can be created from a built-in name, a file on disk, or raw bytes in memory:

```python
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`.

### Transforms

A `Transform` converts pixel data from one profile and format to another:

```python
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

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:

```python
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 `|`:

```python
transform = lcms2.Transform(lab, "Lab_DBL", srgb, "RGB_16",
                            intent="PERCEPTUAL",
                            flags="GAMUTCHECK,SOFTPROOFING")
```

### Applying a transform

`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:

```python
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.

#### Converting a full image

`apply` treats any array shape as `(..., channels)`, so a 2D image `(H, W, C)` is processed in one call:

```python
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 uint16
```

A common use case is editing in Lab — perceptually uniform, so lightness adjustments look natural. OpenCV loads images as BGR uint8:

```python
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:

```python
bgr_out = cv2.cvtColor((result * 255).astype(np.uint8), cv2.COLOR_RGB2BGR)
cv2.imwrite("output.jpg", bgr_out)
```

## Building from source

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](https://github.com/wzjoriv/python-lcms2/issues).

## Acknowledgements

This project is a continuation of work by prior maintainers. The lineage of the repository is:
[sk1-project](https://github.com/sk1-project) → [RomanKosobrodov](https://github.com/RomanKosobrodov/python-lcms2) → [wzjoriv](https://github.com/wzjoriv/python-lcms2).
