Nodes/radiance/SDR to HDR Prepare
ComfyUI Node

SDR to HDR Prepare

The pre-VAE route, and whether you still need it

By FXTD-Studios·Created 8 months ago·Updated about 18 hours ago· 246
SDR to HDR Prepare
  • image
  • clip_mask
  • image
  • mask
  • stats_json
  • peak_linear
◄compression_ratio0.50►
◄inverse_eotfsRGB►
◄highlight_boost4.0►
◄boost_gamma1.5►
◄mask_feather16►

Most people who land here wanted a normal SDR-to-HDR conversion and should be using SDR → HDR Universal instead. Prepare is the older, narrower thing: it gets an SDR image ready to be pushed through a VAE and a sampler so a diffusion model can invent the highlight detail that a clipped 8-bit file threw away. If you don't have a VAE in your graph, you're on the wrong node.

What it's actually for

SDR-to-HDR without a model is a curve - you stretch the highlights you have and call it done. There is nothing above code value 1.0 to stretch, because the camera or the screenshot clipped it. So the interesting version of this job is generative: encode the SDR image into latent space with above-white energy already present, let a sampler fill in plausible specular detail, then decode back to linear. Prepare is the first half of the second path.

The author's own docstring spells the four steps out: decode the display transfer curve to scene-linear, push clipped regions above 1.0 with a power-curve extrapolation, compress that back into 0–1 so a VAE will accept it, and emit per-channel normalisation stats the decoder inverts afterwards. Output image is VAE-ready. Output mask is the feathered inpainting mask - the region the model is allowed to make up.

That mask is the whole trick, and it's why clip_mask is a required input: it comes from Clip Detector, and only inside it do highlights get boosted. Everything outside is left alone.

The inputs that matter

clip_mask (MASK) - run Clip Detector first. Same size as the image, or you get a size error at queue time rather than a warning.

compression_ratio (FLOAT, 0–1, default 0.5) - the author's tooltip: "Must match RadianceHDRDecoder. Wire from preset or LoRALoader." This is the soft-knee compression applied to fit the expanded values into a VAE-friendly range, so encoder and decoder have to agree on it. Mismatch it and your highlights come back shifted - not obviously broken, just wrong.

inverse_eotf - the transfer curve of your source. Get this right or everything downstream is off: sRGB for web images, Rec.709 for video stills, Gamma 2.2, or Linear (no-op) if the pixels are already linear.

Then the two taste controls. highlight_boost (default 4, up to 32) is how far above white you push, in stops: 4.0 is 2 stops. boost_gamma (default 1.5) sharpens the ramp into specular peaks. And mask_feather (default 16 px) softens the inpainting edge so the seam doesn't show.

Outputs are image, mask, stats_json (the norm stats the decoder needs) and peak_linear (the estimated scene-linear peak after extrapolation - useful for sanity-checking your boost before you wait on a sampler).

Install

The pack ships 147 visible nodes, GPL-3.0, by FXTD Studios.

  1. ComfyUI Manager → search Radiance → Install → restart → refresh the browser.
  2. Manual:
cd ComfyUI/custom_nodes
git clone https://github.com/fxtd-studios/radiance.git
cd radiance
python -m pip install -r requirements.txt

Windows portable users: run that pip line with python_embeded\python.exe. The requirements are not trivial - OpenEXR, OpenImageIO, opencolorio, transformers, scipy, tifffile - and the pack's install.py re-checks OpenEXR, OpenColorIO, diffusers and accelerate after a Manager install. One real trap: the Comfy Registry currently serves an older release (2.3.3) than the README's 3.5.0, so if you want the current behaviour use Update in Manager or git pull inside the folder. Python 3.10–3.13; on 3.14 there's no OpenEXR wheel and EXR I/O falls back to OpenImageIO, then OpenCV.

Where people get burned

You may simply not need this node. Radiance 3.5.0 retired the latent-space RUDRA decoders - the ones this node's stats_json was written to feed - and the direct pixel model now handles SDR-to-HDR without a VAE at all. Prepare survives for the VAE/sampler/inpaint route; the current default path is Universal.

If you do run it: a mismatch between compression_ratio here and in the decoder is the classic silent failure, and the per-channel stats output exists precisely so you don't have to remember the numbers. Keep mask_feather off zero unless you like hard seams, and check peak_linear before sampling - if your boost is absurd, you'll see it in that number rather than after a five-minute render.

CategoryFXTD STUDIOS/Radiance/HDR

Inputs (7)

NameTypeDefaultDescription
imageIMAGEDisplay-encoded SDR image, decoded to linear with inverse_eotf.
clip_maskMASKClip mask from Clip Detector, same size as image. Highlights are boosted inside it and it becomes the feathered inpainting mask output.
compression_ratioFLOAT0.500–1Must match RadianceHDRDecoder. Wire from preset or LoRALoader.
inverse_eotfoptCOMBOsRGBTransfer curve of the input, decoded to linear before the highlight boost. Linear (no-op) only clamps negatives.
highlight_boostoptFLOAT4.01–32How bright to push extrapolated highlights in scene-linear. 4.0 = 2 stops above white. Higher = more vivid reconstructed highlights.
boost_gammaoptFLOAT1.50.5–4Power curve for highlight boost ramp. Higher = sharper specular peaks.
mask_featheroptINT160–128Gaussian feather radius on the inpainting mask edge (pixels).

Outputs (4)

NameTypeDescription
imageIMAGE—
maskMASK—
stats_jsonSTRING—
peak_linearFLOAT—