Nodes/radiance/◎ Radiance Float32 Color Correct
ComfyUI Node

◎ Radiance Float32 Color Correct

Color correction with the order a colorist actually uses

By fxtdstudios·Created 7 months ago·Updated 9 days ago· 242
◎ Radiance Float32 Color Correct
  • image
  • image
exposure0.0
contrast1.00
brightness0.00
saturation1.00
gamma1.00
lift_r0.00
lift_g0.00
lift_b0.00
gain_r1.00
gain_g1.00
gain_b1.00
luma_spaceRec.709 / sRGB
clamp_outputfalse

Most "color correct" nodes in ComfyUI are one slider deep: brightness here, saturation there, applied in whatever order the author got bored in. Float32ColorCorrect is not that. It's a proper lift/gamma/gain color corrector - exposure, contrast, saturation, gamma, brightness, plus per-channel lift and gain - running in 32-bit float, and it applies everything in the order a working colorist would.

The order is the whole story. The source is explicit about fixing it in v2.1, and the chain it settled on is: lift → exposure → gain → contrast → gamma → saturation → brightness. Lift (shadow offset) first, because you want to establish the black point before you touch anything else. Exposure as a multiplicative stop, then per-channel gain. Contrast pivots around 0.18 - linear mid-gray, 18% reflectance - not 0.5, because pivoting linear data at 0.5 shoves your actual midtones around. Gamma goes after contrast, saturation uses proper luminance weights, and brightness is an additive offset that lands last so it works in the output space. Each of those decisions is a fix note in the source with the bug it killed.

Why 32-bit float matters

Everything here runs in fp32, and the output defaults to not clamping - clamp_output is off. That means super-whites above 1.0 and valid wide-gamut negatives survive the round trip instead of getting flattened to [0,1]. The gamma function is sign-preserving for the same reason. If you're working on EXR or HDR data, that's the difference between a node you can grade with and a node that quietly destroys your highlight headroom and calls it "normalized."

The cost of that discipline: an 8-bit PNG in gets the same math, but the precision is wasted, and if you feed it SDR content and forget to clamp, you'll see values float above 1.0 downstream. Set clamp_output to true if your chain ends in a normal viewer.

The inputs that matter

  • exposure (stops, ±10) and contrast (multiplier around 0.18) - your two main knobs. +1 stop doubles brightness, and contrast pivots at true mid-gray.
  • saturation - colorspace-aware, with a luma_space selector (Rec.709/sRGB, ACEScg/AP1, Rec.2020). This is a small detail with a big consequence: saturation in ACEScg should use AP1 luminance weights, not Rec.709's, and the node lets you pick. Most correctors just hardcode one.
  • gamma (<1 brightens midtones, >1 darkens) - the power curve you reach for when an image reads "flat."
  • lift_r/g/b and gain_r/g/b - per-channel shadow offset and highlight multiplier. This is where you fix a white balance cast without touching exposure.
  • brightness - additive, last, output space.

Fast path: if every control is at default, the node returns the input untouched - no pointless copy, no precision loss on images you only pass through.

Where it fits

This is a grade, so it belongs after you've converted into linear and before you tone-map or run the ACES output transform. The honest competitor is FXTD_RadianceGradeApply (the Radiance Grade node's bake), which shares the philosophy but exposes the viewer-style control set; Float32ColorCorrect is the one that's just a clean colorist's corrector with per-channel control and none of the preset machinery.

Install

Part of the Radiance pack - ComfyUI Manager → search Radiance, or:

cd ComfyUI/custom_nodes
git clone https://github.com/fxtdstudios/radiance.git
cd radiance
pip install -r requirements.txt

Restart. It lives under FXTD Studios/Radiance/Color.

CategoryFXTD Studios/Radiance/Color

Inputs (14)

NameTypeDefaultDescription
imageIMAGEInput image to color correct. Processed in 32-bit float precision.
exposureFLOAT0.0-10–10Exposure adjustment in stops. +1 = double brightness, -1 = half brightness.
contrastFLOAT1.000–4Contrast multiplier around mid-gray (0.18 in linear). >1 = more contrast, <1 = less.
brightnessFLOAT0.00-1–1Additive brightness offset. Applied last so it works in the final output space.
saturationFLOAT1.000–3Color saturation. 0 = grayscale, 1 = original, >1 = boosted.
gammaoptFLOAT1.000.1–4Gamma correction (power curve). <1 = brighten midtones, >1 = darken. Sign-preserving for HDR.
lift_roptFLOAT0.00-0.5–0.5Red channel lift (shadow offset). Applied first in the chain.
lift_goptFLOAT0.00-0.5–0.5
lift_boptFLOAT0.00-0.5–0.5
gain_roptFLOAT1.000–2Red channel gain (multiplier). Applied after lift, before contrast.
gain_goptFLOAT1.000–2
gain_boptFLOAT1.000–2
luma_spaceoptCOMBORec.709 / sRGBLuminance weights for saturation. Match your working colorspace.
clamp_outputoptBOOLEANfalseClamp output to [0,1]. OFF = HDR pass-through (preserves super-whites/negatives).

Outputs (1)

NameTypeDescription
imageIMAGEColor corrected image in 32-bit float.