Skip to main content

Chromapair

Chromapair learns a deterministic, reusable color transform from spatially aligned areas in a source image and a reference image. It exports either three 256-entry RGB lookup tables or a regularized RGB polynomial, selected by the lowest four-fold cross-validated CIEDE2000 error.

It is image- and layout-agnostic:

  • dimensions come from the input images by default;
  • a smaller source can be positioned inside a reference canvas;
  • one area or several disjoint areas can be fitted together;
  • averaging tile size is calculated automatically and edge tiles need not divide evenly;
  • output is stable, validated JSON that can be applied from the CLI or Python.

Install

Chromapair requires Python 3.11 or newer and is tested with Python 3.14.

uv tool install git+https://github.com/alixsep/chromapair.git
chromapair --help

After a PyPI release, uv tool install chromapair works as well. For development:

git clone https://github.com/alixsep/chromapair.git
cd chromapair
uv sync --extra dev
uv run pytest

Fit and apply

With no area, the full overlap between the source and reference is used:

chromapair fit \
  --source source.png \
  --reference reference.png \
  --name warmer

The reference retains its natural dimensions and the source starts at (0, 0). Apply the generated preset to the original source or another image:

chromapair apply \
  --preset output/presets/warmer.json \
  --input another-source.png \
  --output warmer-output.png

The output format is selected from its extension. RGB is transformed while dimensions and transparency are preserved. Existing outputs are protected unless --force is supplied.

Fit multiple areas

Coordinates use exclusive right and bottom bounds. Repeat --area as needed:

chromapair fit \
  --source texture.png \
  --reference proxy.png \
  --name violet \
  --canvas-size 813 1185 \
  --source-origin 28 28 \
  --area 35 204 67 844 \
  --area 71 1084 426 1109

--canvas-size resizes the reference with Lanczos resampling. The source is never resized or modified; --source-origin only establishes aligned coordinates. Every selected area must be covered by both images.

By default Chromapair aims for about 512 spatial samples:

sample size = floor(sqrt(total selected pixels / target samples))

Each area is tiled independently. Partial tiles along the right and bottom edges are averaged normally, so area dimensions do not need to share factors. Use --target-samples N to adjust the automatic tradeoff, or --sample-size N for an explicit, reproducible override.

Other useful options:

chromapair fit --help
chromapair fit ... --no-previews
chromapair fit ... --preset-output path/to/preset.json
chromapair fit ... --metadata '{"target":"frame"}'
chromapair apply ... --force

Batch configuration

Run all four checked-in examples with:

chromapair batch --config examples/batch.json --no-previews

Paths are relative to the config. areas accepts either one rectangle:

"areas": [35, 204, 67, 844]

or multiple rectangles:

"areas": [
  [35, 204, 67, 844],
  [71, 1084, 426, 1109]
]

Defaults are merged into every job. See examples/batch.json for the complete version-1 format.

The combined bundle produced by a batch can be applied directly:

chromapair apply \
  --preset examples/presets.json \
  --preset-name example-1 \
  --input examples/input-1.webp \
  --output result.png

Examples

These examples deliberately start with altered inputs and learn the inverse transform from each aligned reference. Every output below was produced by Chromapair using examples/batch.json and the checked-in presets.

Example Altered input Reference Chromapair output
1. Hue shift
Hue shifted by -150.
Blue hue-shifted hoodie input Pink hoodie reference Recovered pink hoodie output
2. Contrast, brightness, and size
Reduced to 80% contrast and darkened by 30%. The 64×64 reference is resized to the input's 512×512 canvas for fitting; the output remains 512×512.
Dark low-contrast glass input Glass sculpture reference Restored glass output
3. Saturation and inversion
Saturated by 50% and inverted.
Saturated inverted penguin input Penguin reference Recovered penguin output
4. Selective color shift
Pink foliage shifted toward purple.
Purple-shifted landscape input Pink landscape reference Recovered pink landscape output

Output

A single fit writes:

output/
├── presets/<name>.json
├── reports/<name>.json
└── <name>/
    ├── reference-areas.png
    └── selected-source.png

The preset contains the transform and reproducibility metadata. The report contains geometry, resolved sampling, all candidate errors, selection, and a SHA-256 of the canonical pretty-printed preset.

Chromapair compares an RGB histogram LUT with regularized degree 1, 2, and 3 RGB polynomials. Model selection uses averaged, spatially corresponding samples. Final histogram fitting and quality metrics use every selected visible pixel. Fully transparent source pixels are ignored. Source alpha is preserved in preview and applied output.

Presets are validated before they are written or applied. Invalid format versions, methods, LUT lengths, polynomial terms, coefficient shapes, and non-finite numeric values are rejected with a clear error.

Python API

import json
from pathlib import Path

from PIL import Image

from chromapair import apply_preset, validate_preset

preset = json.loads(Path("preset.json").read_text())
validate_preset(preset)

with Image.open("input.png") as image:
    output = apply_preset(image, preset)

output.save("output.png")

apply_preset returns a new image and does not modify its input.

Determinism

Chromapair has no random fitting step. Tiles, fold assignments, candidate ordering, coefficient rounding, JSON key ordering, and output hashing are deterministic. Lock dependencies with the checked-in uv.lock when exact cross-machine reproduction matters.

License

MIT

Metadata

Release files for chromapair 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for chromapair 1.0.0
File Size Uploaded
chromapair-1.0.0.tar.gz 1.3 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for chromapair 1.0.0
File Interpreter ABI Platform
chromapair-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 1.3 MB

Release files / chromapair-1.0.0.tar.gz

Download URL chromapair-1.0.0.tar.gz
Size 1.3 MB
Tags Source
SHA-256 checksum
How to use checksums
ab594428feae9fdab6b1130e21471c68ee620325094aae1df7c464e4b49648d8
BLAKE2b-256 checksum
How to use checksums
8f7f938541774272e83bb86692e28af77436400e19617acf16e785ba655369d3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 28, 2026.

Transparency log

Release files / chromapair-1.0.0-py3-none-any.whl

Download URL chromapair-1.0.0-py3-none-any.whl
Size 15.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a5406b366c6a28d1a4922e7c893f9ca0138c31ef93e81715413270b173bb244d
BLAKE2b-256 checksum
How to use checksums
e0b973c2731bf6b019551dc2d8e1c8d0d605fe8db772706360a379276bd8ef57
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 28, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page