C2C ACES Tonemap
The filmic tone-mapping node that makes overbright AI output look like a graded frame instead of a blown-out mess
- image
- IMAGE
Diffusion models love to clip. Highlights slam into pure white, shadows crush to black, and the result looks fine on a phone and terrible in a real grade. ACES tonemapping is the film-industry fix: a curve that rolls off highlights instead of clipping them, so overbright pixels come back with color and smooth falloff instead of a wall of white. C2CACESTonemap wraps that in a single node with exposure, contrast, and saturation controls - the "make it look like a frame" button.
If you've ever tried to composite AI output into a VFX pipeline, you already know the deeper problem this sits next to: ComfyUI hands you 8-bit-ish sRGB tensors in a 0–1 range, while a real pipeline works in scene-linear float (the KB's post-processing doc walks through exactly that mismatch). This node is the bridge - linearize, tone map, and hand back something display-ready.
How it works
The implementation (in nodes/hdr_color_science.py) is a clean-room version of the standard ACES filmic curve - the Stephen Hill approximation you'll find in Unity and Unreal. In order: it linearizes from your chosen source space (sRGB or ARRI Log C3; "Linear" passes through), applies an exposure multiplier, does contrast around mid-gray 0.18 in log space, adjusts saturation along a Rec.709 luma axis, then runs the ACES filmic curve and encodes to your output space. It's pure PyTorch tensor math - no models, no VRAM, no dependencies.
The inputs
- source_space - what the input is encoded as:
sRGB,Linear, orLog C3. Get this wrong and everything is wrong, so be honest about what you're feeding it. - exposure (1.0) - multiplier before tonemapping; up to 10× if you're rescuing a dark pass.
- contrast (1.0) - log-space contrast, 0.5–2.0.
- saturation (1.0) - below 1 desaturates, above 1 boosts.
- output_colorspace -
sRGB (gamma)for display,Linearif you're compositing further, orACES AP1if you're handing off to a real ACES-managed comp.
Output is a single IMAGE.
Installing it
Part of the Code2Collapse/ComfyUI-CustomNodePacks umbrella pack. ComfyUI Manager → search "CustomNodePacks", or:
cd ComfyUI/custom_nodes
git clone https://github.com/Code2Collapse/ComfyUI-CustomNodePacks.git
Restart ComfyUI. No extra dependencies for this node. (The pack's requirements.txt has opencv-python and scipy for its other nodes; install only what you're actually missing rather than a blanket pip install -r requirements.txt over ComfyUI's bundled torch/numpy.)
Gotchas
The classic mistake is feeding it an already-gamma-encoded image while telling it the source is linear - you'll get washed-out, milky output and blame the node. Match source_space to reality. For typical ComfyUI output, sRGB-in → sRGB-out with exposure around 1.0 and the default contrast/saturation is a huge upgrade over raw output on overbright scenes; keep it there until you know why you're deviating. If you're chaining this before other color work, output Linear and do the sRGB encode last, or you'll double-gamma everything. It's a small node with a big, easy win - put it at the end of a Wan or Flux pipeline and A/B it once.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| source_space | COMBO | sRGB | Input color space. The image is linearised from this space before ACES processing. |
| exposure | FLOAT | 1.000.01–10 | Exposure multiplier applied before tone mapping. |
| contrast | FLOAT | 1.000.5–2 | Contrast adjustment (applied in log space). |
| saturation | FLOAT | 1.000–2 | Color saturation. <1 desaturates, >1 boosts. |
| output_colorspace | COMBO | sRGB (gamma) | Output color space. sRGB for display, Linear for compositing. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |