Nodes/WAS Node Suite v3/Image Tone Map
ComfyUI Node Runs on cloud

Image Tone Map

Roll those >1.0 highlights down before they hit an 8-bit save

By WASasquatch·Created 3 years ago·Updated 4 days ago· 1,844
Image Tone Map
  • images
  • images
  • peak
  • recovered
operator
exposure0.0
white_point4.0
applied_to
output

If you've ever done HDR work in ComfyUI you've met the problem: HDR Reconstruct, HDR VAE Decode and EXR Load all answer linear light - numbers where a blown highlight isn't 1.0, it's 4.0 or 40.0. The instant you preview that or save it as an 8-bit PNG, everything above white cuts to pure white and the highlight detail is gone. WAS Image Tone Map is the bridge: it rolls those above-1.0 values down into a range a screen can show, with a curve instead of a guillotine.

The operator dropdown is the whole personality of the node. aces and hable are the filmic choices - they give the gentle "shoulder" a camera has as it approaches white, at the cost of darkening midtones a little. reinhard never clips at all (gentle, never quite reaches white), drago holds detail furthest into a very bright highlight, and clip is the plain cut at 1.0 - included so you can see what you're replacing. For most work, aces or hable is where you land; the difference between the two is subtle enough that you'll pick by taste.

Then exposure, in stops, applied before the curve: -2.0 quarters the brightness and pulls a blown highlight back into the shoulder. This is the recovery dial - if your frame's highlight hit 40× white, you don't need a fancier operator, you need a couple of stops of negative exposure so the curve has something to work with.

Two further choices decide how the map is applied. white_point (default 4.0) sets what level comes out as white - only read by reinhard extended and drago. At 4.0, a value four times diffuse white reaches 1.0; push it to 40 to keep a rebuilt sun inside the curve. And applied_to picks each channel (maps red, green and blue on their own - washes a saturated highlight toward white the way film does) versus brightness (maps brightness and scales the three together, keeping hue). Finally, output decides whether the result gets the sRGB curve baked in (picture codes, what a preview/PNG/JPEG expect) or stays linear (linear light, for further grading or an EXR).

What elevates this from "another HDR node" is the diagnostic outputs. Alongside images it returns peak - the largest value that went into the curve after exposure (40.07 tells you the frame held a highlight 40× white; 1.0 means nothing was above white and the curve only darkened the picture) - and recovered, the share of pixels that were above 1.0 and came back inside it (0.03 = 3% of the frame was rolled down rather than cut to white). Wire those into a display or a log and you get hard numbers on whether your highlight recovery actually happened. It's the difference between guessing and knowing, and it's rare to see a tone-mapping node tell you its own score.

The classic chain: HDR Reconstruct (or EXR Load) → grade → Image Tone Map → Image Preview or a PNG save. The KB's color-management corner warns this world is all-or-nothing - once you carry light above white you need the whole linear-light pipeline - and this node is the "out" at the end that makes it printable.

Install

Ships in WAS Node Suite v3. ComfyUI Manager, search "WAS Node Suite", or:

cd ComfyUI/custom_nodes
git clone https://github.com/WASasquatch/was-node-suite-comfyui

Restart after. Needs ComfyUI 0.14.0+ and Python 3.10+, no pip packages or model downloads. (v3 ships clean - the v2 pack's dependency baggage is gone.)

Common issues

  • Highlights still clip flat. Check peak first - if it's enormous, add negative exposure so the curve isn't fed values beyond its shoulder.
  • Everything looks dark after mapping. aces/hable darken midtones; add a little positive exposure or pick reinhard.
  • Result saves wrong. output set to linear light stays linear - if you're saving a PNG/JPEG, use picture codes.
CategoryWAS Suite/Image/HDR

Inputs (6)

NameTypeDefaultDescription
imagesIMAGEThe frames to map, as linear light. Wire in HDR Reconstruct, HDR VAE Decode, EXR Load, or Linear Light on `sRGB to linear`.
operatorCOMBOThe curve the highlights roll down. `aces` and `hable` are filmic and darken the midtones a little; `reinhard` is gentle and never quite reaches white; `drago` holds detail furthest into a very bright highlight; `clip` cuts at 1.0.
exposureFLOAT0.0-16–16Stops applied before the curve. 0.0 = as it arrived, -2.0 = a quarter as bright, which pulls a blown highlight back into the shoulder, +1.0 = twice as bright.
white_pointFLOAT4.01–1000The level that comes out as white. 4.0 = four times diffuse white reaches 1.0; 40.0 keeps a rebuilt sun inside the curve. Read by `reinhard extended` and `drago` only.
applied_toCOMBO`each channel` maps red, green and blue on their own, which washes a saturated highlight towards white the way film does; `brightness` maps brightness and scales the three together, keeping the hue.
outputCOMBO`picture codes` applies the sRGB curve, which is what a preview, a PNG and a JPEG expect; `linear light` leaves the result linear, for more grading or an EXR.

Outputs (3)

NameTypeDescription
imagesIMAGEThe mapped frames, in 0 to 1.
peakFLOATThe largest value that went into the curve, after exposure. 40.07 = the frame held a highlight 40 times white; 1.0 = nothing was above white and the curve only darkened the picture.
recoveredFLOATThe share of pixels that were above 1.0 and came back inside it. 0.0 = nothing was clipping; 0.03 = 3% of the frame was rolled down rather than cut to white.