HDR Analysis
Is your output actually HDR, or just bright?
- image
- peak_nit
- ev_range
- clipped_pct
- is_hdr
- stats_json
Everyone claims their pipeline "does HDR" now. Most of what people are actually looking at is a tone-mapped preview on an SDR monitor, and there is no way to tell the difference by eye. HDR Analysis is the honesty node: feed it an image and it tells you the peak luminance in nits, the dynamic range in stops, what fraction of the frame is clipped, and - the useful one - a plain boolean for whether there's any HDR content at all.
That boolean is the reason to wire it in. In a ComfyUI graph it turns "did the model actually reconstruct highlights?" from an opinion into a branch condition. Peak numbers also feed straight into delivery: if you're encoding HDR10 later, you want to know whether your scene peaks at 250 nits or 4000 before you pick a mastering peak.
How it works
The node anchors on BT.2408, where scene-linear 1.0 is 203 nits - standard SDR diffuse white. Luma above 1.0 therefore counts as above SDR white, which is exactly the definition of HDR content. From the flattened pixel data it takes percentiles: ev_range is the spread in stops between the 1st and 99th percentile luma, peak_nit is derived from the peak, and clipped_pct is the share of pixels sitting above linear 1.0. Luma coefficients are switched for ACEScg (AP1) versus the sRGB-ish default, which is why the colorspace setting isn't decoration.
It's fast by design: images over 500k pixels are measured on a strided subsample. You lose a little precision, you don't wait.
Inputs and outputs
One required input, image, and one optional to actually get right: colorspace. Nine options - Linear (sRGB), sRGB (Standard), the four camera logs (ARRI LogC3/LogC4, Sony S-Log3, Panasonic V-Log), DaVinci Intermediate, ACEScg, ACEScct. The tooltip is explicit that Linear (sRGB) is correct for Radiance Decode output, and that log spaces get linearised first so the nit estimate is meaningful. Get this wrong and you get confident nonsense: measuring an sRGB-encoded file as if it were linear exaggerates shadows and under-reports peak.
Five outputs, and only two of them usually get wired:
is_hdr(BOOLEAN) - true whenpeak_nitis above 203. Branch on this.stats_json(STRING) - the full zone statistics as JSON, for logging or a text-preview node.peak_nit,ev_range,clipped_pct- the numbers, for feeding a HDR Encode node's peak choice or just watching them during iteration.
Note that HDR Diagnostics in the same pack supersedes this node - its own description says it replaces the separate HDR Analysis node while keeping the same live metric floats. If you're starting a fresh graph on this pack, reach for Diagnostics; if your graph already uses HDR Analysis, it still works.
Install
Manager → search Radiance → Install → restart → refresh the browser. Manually:
cd ComfyUI/custom_nodes
git clone https://github.com/fxtd-studios/radiance.git
cd radiance
python -m pip install -r requirements.txt
No model downloads. Windows portable users: run that pip line with python_embeded\python.exe.
Where people get burned
Mismatched colorspace is the whole failure mode, and it fails quietly. A log-encoded frame measured as Linear (sRGB) won't error - it'll just report a peak nit number that's wrong by a factor you can't see. If is_hdr says false on something you're sure is HDR (or true on a flat grey card), suspect this field first.
Second, treat is_hdr as a statement about this tensor right now, not about your source. If an upstream node clamped to 0–1, the analysis is correct and the answer is that your pipeline already ate the highlights. Walk back up the graph until the boolean flips; that's where the range died.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | Image to measure; set colorspace to match its encoding. Luma above 1.0 counts as above SDR white (203 nits). Images over 500k pixels are measured on a strided subsample. | |
| colorspaceopt | COMBO | Linear (sRGB) | Colorspace of the incoming image. 'Linear (sRGB)' is the correct setting for Radiance Decode output. Log spaces are linearised first for accurate nit estimation. |
Outputs (5)
| Name | Type | Description |
|---|---|---|
| peak_nit | FLOAT | Estimated peak luminance in cd/m² (BT.2408 anchor: 203 nit = linear 1.0). |
| ev_range | FLOAT | Dynamic range in stops (EV) between p01 and p99 luma. |
| clipped_pct | FLOAT | Percentage of pixels above scene-linear 1.0 (clipped for SDR display). |
| is_hdr | BOOLEAN | True when peak_nit > 203 — image contains HDR content above SDR white. |
| stats_json | STRING | Full zone statistics as JSON. |