◎ Radiance HDR Shadow/Highlight Recovery
Pulling detail out of the shadows and highlights — without clipping anything
- image
- recovered_image
Every image you've ever graded has the same tension: lift the shadows and the blacks turn gray and muddy; pull the highlights down and the whites go flat. HDRShadowHighlightRecovery is the Radiance node that does both at once, on a single image, in float32, with separate control over where the shadow and highlight zones sit.
The trick it pulls off is worth understanding because it's why this isn't just a contrast slider in a costume. It computes luminance, then builds masks: shadows get an exponential-decay mask (full at black, falling to zero by the shadow_tone point), highlights get a sigmoid-style mask that stays at zero until the highlight_tone and keeps rising above 1.0 - so it works on super-whites too, not just "pixels between 0.5 and 1.0." Shadows get boosted by the shadow_amount, highlights get softly compressed by the reciprocal of the highlight amount. Because it's all masks over a float image, nothing gets hard-clipped; the detail that was there comes back and the values that were above 1.0 stay above 1.0.
The inputs
- shadow_amount / highlight_amount (0–2, default 0.5 each) - how hard to recover each end. Start at 0.5, nudge up.
- shadow_tone (0–0.5, default 0.25) - where the shadow zone ends. Lower = only the deepest shadows get lifted.
- highlight_tone (0.5–1, default 0.75) - where highlight compression begins. Lower it to start taming highlights earlier.
- color_correction (0–1, default 0.5) - the subtle but important one: lifted shadows desaturate fast, so this pulls saturation back toward the luminance to keep shadows from going purple/green.
- local_contrast (−1 to 1, default 0) - a Gaussian-based local contrast pass (GPU-accelerated when available, scipy fallback otherwise) for adding midtone pop after recovery.
Output: recovered_image, float32.
Where it fits
This is a recovery, not a hallucination. The source masks work on detail that exists in the data - lifting shadows reveals what's already recorded there. If your shadow detail was crushed to pure black in an 8-bit export, there's nothing to reveal, and the README's standing warning applies: no Radiance node can recover detail that was clipped upstream. Where this shines is the typical AI-generation case: the model produced a float image with a wide tonal range, and the shadows are technically there but sitting below your display's ability to show them.
Pipeline-wise: run it after you're in linear (or right on the VAE output), then tone-map to finish. It pairs naturally with HDRExpandDynamicRange - expand for headroom, then recover the ends - though for most people this single node is the whole fix.
Install
Part of Radiance - 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. Under FXTD Studios/Radiance/Color.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| shadow_amount | FLOAT | 0.500–2 | — |
| highlight_amount | FLOAT | 0.500–2 | — |
| shadow_toneopt | FLOAT | 0.250–0.5 | — |
| highlight_toneopt | FLOAT | 0.750.5–1 | — |
| color_correctionopt | FLOAT | 0.50–1 | — |
| local_contrastopt | FLOAT | 0.0-1–1 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| recovered_image | IMAGE | — |