Skip to content

Repository files navigation

camicc

Disclaimer: this project was written almost entirely by an LLM (Claude), directed and reviewed by a maintainer who does not claim a deep understanding of the color-science math behind the DCP → ICC conversion. Treat the pipeline as empirically validated rather than expert-reviewed: every published number and image is reproduced by the automated harness in testing/ against real out-of-camera JPEGs and Adobe (Lightroom) renderings. Corrections from people who know this domain are very welcome.

Convert DNG camera profiles (.dcp) into ICC input profiles that reproduce the camera's color rendering inside darktable.

darktable cannot read DCP camera profiles — the format used by Adobe and RawTherapee to describe how a camera's colors should be rendered. The usual advice is to convert DCP to ICC with dcamprof, but its conversion is matrix-based: the HueSatMap and LookTable are not carried over — and those 3D color tables hold most of the "camera look" (hue rotations and saturation boosts, e.g. up to 1.7× on skin tones), so a matrix-only profile renders noticeably flatter than the camera.

camicc implements the full DNG color pipeline instead:

white-balanced camera RGB
  → ForwardMatrix → XYZ (D50)
  → linear ProPhoto HSV
  → HueSatMap        (dual-illuminant, linear or sRGB encoding)
  → LookTable        (3D, value axis, sRGB encoding)
  → tone curve       (per RGB channel, like the camera; or hue-preserving)
  → CIELAB

…sampled into a 33³ CLUT and written as a self-contained ICC v2 profile that darktable (via LittleCMS2) applies as an input color profile.

How close does it get?

Test scene: Canon EOS RP raw (.CR3), DCP: Adobe's "Camera Standard" profile for the EOS RP. All numbers are the mean absolute pixel difference on the central 80% of the frame (0–255, lower is better; ≲5 is hard to tell apart by eye), produced by the reproducible harness in testing/ inside its pinned Docker image.

The fair benchmark is Adobe's own rendering, not the camera JPEG. camicc converts Adobe's DCP, so the ground truth for the conversion is what Adobe's pipeline (Lightroom / Camera Raw) produces from the same raw with that DCP. The camera JPEG adds in-camera processing (auto lighting optimization, per-image tweaks, sharpening) that no DCP contains — not even Lightroom matches it exactly. Against a Lightroom export:

vs Lightroom

Rendering mean diff vs Lightroom
darktable + camicc "(camera look)" 4.1
Camera JPEG (Picture Style Standard) 7.6
darktable + camicc "(colors only)" + sigmoid 10.2
darktable factory default (sigmoid, standard matrix) 10.5
RawTherapee default (native DCP) 11.4

camicc (camera look) lands closer to Lightroom than the camera's own JPEG does — the DCP pipeline (color tables + tone curve) survives the conversion to ICC essentially intact. Even RawTherapee, which reads the DCP natively but applies its own per-image curve, is further away.

The two profile variants

Each DCP converts into two ICCs:

  • (camera look) carries the DCP tone curve inside the profile — the faithful match above (4.1), at the price of switching darktable's own tone mapping off.
  • (colors only) carries only the DCP color tables and leaves the tone curve to darktable's scene-referred tone mapper (sigmoid / filmic / agx), keeping darktable's full highlight handling. With sigmoid at its defaults it scores 10.2 vs Lightroom — the colors are already right, the entire difference is tone curve shape.

That difference is two sliders away: sigmoid at contrast 1.95, skew −0.225 brings (colors only) to 3.0 vs Lightroom on the same image — matching (camera look), while staying fully scene-referred:

Lightroom vs tuned colors-only

The tuned settings were found automatically by the parameter sweep in testing/. It is not always this close: the optimum shifts with scene content, and on harder scenes (backlit skies, heavy in-camera lifting) even the per-image best sigmoid stays at a visible 5–10 — see the per-image tables and montages for the whole test set.

Install

Every tool in this repo — the converter, the DCP fetcher and the test harness in testing/ — can be used three ways; pick whichever fits your system. (Paths with spaces are shown backslash-escaped throughout — exactly what bash/zsh tab completion produces, no quoting needed.)

1. Natively — any Linux with Python ≥ 3.9 (validated on stock Ubuntu):

sudo apt install innoextract python3 python3.14-venv
python3 -m venv ~/.venvs/camicc && ~/.venvs/camicc/bin/pip install .
export PATH=~/.venvs/camicc/bin:$PATH   # provides camicc, camicc-fetch-dcps

2. Nix (flake):

nix run .# -- --help               # the converter
nix run .#fetch-dcps               # the DCP fetcher
nix develop                        # dev shell for the testing scripts

3. Docker (no Python or Nix on the host — the images are built by Nix internally, so they contain exactly the versions pinned by flake.lock):

docker build -t camicc .
# converter — same arguments as the CLI, current directory mounted at /work:
docker run --rm --user "$(id -u):$(id -g)" -v "$PWD:/work" camicc \
    Canon\ EOS\ RP\ Camera\ Standard
# DCP fetcher:
docker run --rm --user "$(id -u):$(id -g)" -v "$PWD:/work" \
    --entrypoint /fetch/bin/camicc-fetch-dcps camicc

The .icc files are written to an icc/ folder in the mounted directory (--install is not useful inside the container — copy the ICCs to ~/.config/darktable/color/in/ yourself). In Docker, file arguments are resolved inside the container: anything under the current directory works as-is; files elsewhere need their own mount (e.g. -v /path/to/my-dcps:/dcps:ro and pass /dcps/...). The containerized test harness is a separate image: see testing/README.md.

Usage

The workflow is: get the DCPs → run camicc → the ICC lands in darktable's profile folder → select it in darktable.

Step 1 — get DCP files for your camera

The easiest way is the bundled fetcher: it downloads the official Adobe DNG Converter from adobe.com (~1.8 GB) and extracts all of Adobe's camera profiles — including the "Camera Standard/Portrait/…" replicas of each vendor's picture styles — into a local dcps/ folder. Nothing is installed or executed; the installer archive is simply unpacked:

# native (needs innoextract from your distro):
camicc-fetch-dcps                  # -> ./dcps/Camera/<model>/*.dcp
# Nix:
nix run .#fetch-dcps
# Docker:
docker run --rm --user "$(id -u):$(id -g)" -v "$PWD:/work" \
    --entrypoint /fetch/bin/camicc-fetch-dcps camicc

The extracted profiles are copyrighted by Adobe: they are for your own use and must not be committed or redistributed (the dcps/ folder is gitignored). Alternative sources — any .dcp from anywhere on disk works too, e.g. RawTherapee's bundled profiles in /usr/share/rawtherapee/dcpprofiles/, or profiles you made yourself.

Step 2 — convert (and install)

With the default dcps/ folder populated, a bare profile name is enough — camicc looks it up automatically ($CAMICC_DCP_DIR overrides the search locations; ~/.cache/camicc/dcps is also tried):

Profile names may contain wildcards, matched against the default DCP folders — the escaped \* below installs every Camera-style profile of the model at once (6 DCPs: Standard/Portrait/Landscape/Neutral/Faithful/ Monochrome, each as (camera look) + (colors only)). The * must be escaped or quoted, otherwise the shell globs it against your current directory first — zsh even aborts with "no matches found":

# native — convert AND copy into darktable's profile folder
# (~/.config/darktable/color/in/) in one step:
camicc --install Canon\ EOS\ RP\ Camera\ \*
# Nix:
nix run .# -- --install Canon\ EOS\ RP\ Camera\ \*
# Docker (no --install: the container cannot see your darktable config;
# the ICCs land in ./icc, copy them yourself):
docker run --rm --user "$(id -u):$(id -g)" -v "$PWD:/work" camicc \
    Canon\ EOS\ RP\ Camera\ \*

A single profile installs the same way, no wildcard needed:

camicc --install Canon\ EOS\ RP\ Camera\ Standard

Explicit paths work the same, several at once too:

camicc --install /usr/share/rawtherapee/dcpprofiles/Canon\ EOS\ RP.dcp
camicc --install dcps/Camera/Canon\ EOS\ RP/*.dcp

With no profile argument at all, every DCP found in the default folders is converted. Point $CAMICC_DCP_DIR at one camera's folder to convert (and --install) its complete profile set in one go:

CAMICC_DCP_DIR=dcps/Camera/Canon\ EOS\ RP camicc --install

(Without the scoping variable this converts the entire ~4,400-profile tree — hours of work and an unusably long profile list in darktable.)

The generated .icc files always land in a local icc/ folder (or -o <dir>); --install additionally copies them into darktable's profile folder. Without it, copy them manually:

camicc Canon\ EOS\ RP\ Camera\ Standard
mkdir -p ~/.config/darktable/color/in
cp icc/*.icc ~/.config/darktable/color/in/

For Flatpak darktable the profile folder is ~/.var/app/org.darktable.Darktable/config/darktable/color/in/ — use -o and copy there yourself.

Each DCP produces two ICCs, named after the camera and profile name embedded in the DCP, e.g.:

Canon EOS RP Camera Standard (camera look).icc
Canon EOS RP Camera Standard (colors only).icc
  • (camera look) — color tables and the DCP tone curve baked in, applied per RGB channel exactly like the camera/Adobe pipeline. This is the faithful "camera JPEG" rendering.
  • (colors only) — color tables only, no tone curve. Use this if you want the camera's color character but prefer darktable's scene-referred tone mappers (sigmoid / filmic / agx).

Useful flags: --variant look|colors|both, --curve-mode channel|luminance, --cct <kelvin> (interpolate dual-illuminant DCPs at a shot color temperature, e.g. a @3200K profile for tungsten light), --hsm-illuminant 1|2 (tungsten/daylight table for dual-illuminant DCPs), --custom-curve curve.json (fit your own tone curve), --grid N, --name "My name" (override the profile name from the DCP).

Step 3 — select it in darktable

  1. Restart darktable — the profile folder is only scanned at startup.
  2. Open your raw in the darkroom and set input color profile → profile to the new entry (profiles appear under the name shown above).

Step 4 — module settings that make or break it

For the (camera look) profiles the tone curve is already baked in, so darktable's own tone mapping must be off or it is applied twice:

  • disable sigmoid (or filmic rgb / agx) and base curve;
  • set exposure to 0 EV (darktable's default preset adds ≈ +0.5–0.7 EV);
  • set color calibration → adaptation to none (bypass) and use the legacy white balance module set to as shot — the profile expects fully white-balanced camera RGB, like RawTherapee feeds a DCP;
  • optionally enable lens correction (the camera JPEG is vignette-corrected).

For the (colors only) profiles, keep your scene-referred tone mapper (sigmoid / filmic / agx) — but the white balance requirement is the same as above: legacy white balance module at as shot doing the full balancing, color calibration adaptation at none (bypass). Both profile variants expect fully white-balanced camera RGB at their input; the modern workflow's split (white balance at "camera reference (D65)" + color calibration doing the adaptation) feeds the profile wrong values and shifts every color.

Where to get DCP profiles

  • camicc-fetch-dcps (see Step 1) — downloads the free Adobe DNG Converter and extracts its complete profile set (~4,400 DCPs for essentially every camera Adobe supports, including the "Camera Standard/Portrait/Landscape/…" picture-style replicas) into dcps/, without installing or running anything.
  • RawTherapee installs ship high-quality DCPs: share/rawtherapee/dcpprofiles/.
  • Any DCP you made yourself (e.g. with dcamprof + a color target) works too.

This is camera-agnostic: any DCP with a ForwardMatrix converts directly, and for older profiles that only carry a ColorMatrix (e.g. RawTherapee's Canon EOS 5D profile) the forward matrix is derived automatically by inverting the color matrix and Bradford-adapting the calibration illuminant to D50.

Limitations

  • A static ICC cannot re-interpolate DNG's dual-illuminant tables per shot the way Lightroom does. By default the daylight tables are used (--hsm-illuminant); with --cct <kelvin> the matrices and HueSatMap are interpolated at a chosen shot color temperature (e.g. --cct 3200 for a tungsten-light profile, named … @3200K). How much this matters depends on the DCP: Adobe's "Camera *" profiles are usually illuminant-invariant (identical forward matrices, no HueSatMap — their look is all in the LookTable/curve), so --cct changes nothing and says so. "Adobe Standard" and RawTherapee-style profiles carry dual HueSatMaps, where the tungsten tables differ substantially (mean ΔE ≈ 9 and ≈ 16 respectively on the Canon EOS RP profiles) — for warm-light shots with those profiles a --cct build is the right choice.
  • ICC LUT input profiles clamp the unbounded pipeline in darktable; extreme highlight-recovery workflows behave slightly differently than with matrix profiles.
  • RawTherapee's auto-matched tone curve is fitted per image and cannot be a static profile. (camera look) uses the DCP's own curve instead — for Adobe's "Camera *" profiles that is precisely the vendor look.

License

GPL-3.0-or-later for all code in this repository.

Profile licensing notes (not legal advice)

camicc is original code implementing Adobe's openly published DNG specification; it contains no Adobe code or data. The camera profiles it converts have their own owners, so the project draws a deliberate line:

  • Nothing Adobe-derived is redistributed. Adobe's DCPs and any ICC converted from them stay on your machine: camicc-fetch-dcps downloads Adobe DNG Converter from Adobe's own servers at runtime and extracts it locally (the same long-established route documented by RawPedia and packaged e.g. in the AUR); dcps/ and *.icc are gitignored, and the committed test folder carries only a sha256 of the profile it used, never the profile.
  • Local conversion for processing your own photos is what these profiles are for. Adobe tags its profiles with an embed policy; the ones handled here carry "allow copying", which permits copying them onto your system and using them to process any file. Photos you develop with a converted profile are yours.
  • Redistributing or selling converted profiles is the gray zone — a converted ICC embeds Adobe's color tables in another container, which may constitute a derivative work of that data. This project doesn't do it and its tooling never does it for you. If you plan to publish profile packs converted from Adobe (or any third-party) DCPs, get proper legal advice or written permission first; profiles you convert from your own measurements or from freely licensed DCPs (e.g. RawTherapee's community-made ones, GPL) don't have this problem.

About

camicc is a set of scripts for converting dcp camera profiles into icc for darktable

Resources

Stars

Watchers

Forks

Contributors

Languages