Nodes/comfyui-x2hdr/X2HDR Color Grade
ComfyUI Node

X2HDR Color Grade

A full HDR colorist's panel that lives inside ComfyUI — no external app needed

By facok·Created 2 months ago·Updated about a month ago· 3
X2HDR Color Grade
  • hdr_image
  • graded_display
  • graded_linear
exposure0.0
tone_mapACES Fitted
soft_clip0.00
temperature0.00
tint0.00
lift_r0.00
lift_g0.00
lift_b0.00
gamma_r1.00
gamma_g1.00
gamma_b1.00
gain_r1.00
gain_g1.00
gain_b1.00
offset_r0.00
offset_g0.00
offset_b0.00
contrast1.00
pivot0.180
shadows0.00
highlights0.00
saturation1.00
vibrance0.00
hue_shift0
false_colorfalse
auto_exposurefalse
auto_exposure_lockfalse
auto_exposure_ev0.00
matrix_rr1.00
matrix_rg0.00
matrix_rb0.00
matrix_gr0.00
matrix_gg1.00
matrix_gb0.00
matrix_br0.00
matrix_bg0.00
matrix_bb1.00
density0.00
black_lift0.000
shadow_tone_r0.000
shadow_tone_g0.000
shadow_tone_b0.000
highlight_tone_r0.000
highlight_tone_g0.000
highlight_tone_b0.000
tone_balance0.50

Every X2HDR workflow ends the same way: you've got a linear float HDR tensor that looks flat and alien on a normal monitor, and you need to turn it into something you can actually look at - while keeping an HDR master for anyone who needs one. X2HDR Color Grade does both, and it's the pack's headline act.

The headline feature is the interactive viewer. Run the node once, then click Open X2HDR color grade on the node itself. This isn't a third-party plugin bolted on - it's implemented inside the pack (a bit of Python routes plus a JS frontend). The mechanism is that the node caches the HDR tensor on the ComfyUI server, and the viewer requests tone-mapped preview frames over the pack's own HTTP endpoints as you drag sliders. You're grading live, not waiting on full graph re-runs.

The viewer gives you: canvas pan/zoom/fit/1:1, live exposure plus auto exposure, tone mapping, soft clip, white balance, contrast, lift/gamma/gain/offset, shadows/highlights, saturation/vibrance, hue shift, density, black lift, split toning, a 3×3 color matrix, false color, source/graded/split comparison, an RGB histogram, HDR and display pixel sampling, frame navigation for batches, and factory plus user presets. Hit Save and it writes your values back to the node's widgets; Save PNG and Save EXR export the current frame through the pack's backend.

Inputs a beginner actually sets

  • tone_map - None / Reinhard / ACES Fitted / AgX / Hable. ACES Fitted is the default and the right starting point: it's the classic filmic curve and handles the bright end far better than Reinhard's gentle squash.
  • exposure (EV) and soft_clip - the two dials that rescue a blown-out or dim grade.
  • temperature / tint for white balance, saturation / vibrance for color, contrast with its pivot (default 0.18, i.e. mid-gray).
  • false_color - a boolean that shows you clipping instead of making you guess.

Everything else in the required list is the standard per-channel lift/gamma/gain/offset trio, and the optional section hides auto-exposure, the color matrix, density, black lift and split-toning controls. Ignore those until you feel limited; the viewer exposes all of it anyway.

Outputs

  • graded_display (IMAGE) - the LDR display render. Wire it to a normal Save Image or Preview Image.
  • graded_linear (IMAGE) - the same grade, still linear HDR. This is your HDR master; wire it to X2HDR Save EXR if you want a graded EXR rather than the raw decode.

Feed it the hdr_image output of any X2HDR decode (PU21, LogC3 or LogC4). The full pipeline is decode → (QA) → save raw EXR → color grade → save display PNG plus graded EXR.

Installing it

ComfyUI Manager → search comfyui-x2hdr → install, restart, nodes under image/HDR/X2HDR. Or:

cd ComfyUI/custom_nodes
git clone https://github.com/facok/comfyui-x2hdr

then restart. The one extra dependency is PyAV (av), declared in pyproject.toml; it's imported at load time, so if the pack fails to import, pip install av in ComfyUI's Python env fixes it.

Gotchas

  • The viewer only shows content after you've run the node once - that's when the tensor gets cached on the server.
  • Don't save graded_display and call it your HDR. It's an LDR preview, gamma-encoded; the HDR lives in graded_linear / the EXR. This is the classic sRGB-vs-scene-linear trap from the color-management world, and it's what trips up people handing AI output to a compositor.
Categoryimage/HDR/X2HDR

Inputs (47)

NameTypeDefaultDescription
hdr_imageIMAGE
exposureFLOAT0.0-10–10
tone_mapCOMBOACES Fitted5 options: None, Reinhard, ACES Fitted, AgX, Hable
soft_clipFLOAT0.000–1
temperatureFLOAT0.00-1–1
tintFLOAT0.00-1–1
lift_rFLOAT0.00-1–1
lift_gFLOAT0.00-1–1
lift_bFLOAT0.00-1–1
gamma_rFLOAT1.000.1–4
gamma_gFLOAT1.000.1–4
gamma_bFLOAT1.000.1–4
gain_rFLOAT1.000–4
gain_gFLOAT1.000–4
gain_bFLOAT1.000–4
offset_rFLOAT0.00-1–1
offset_gFLOAT0.00-1–1
offset_bFLOAT0.00-1–1
contrastFLOAT1.000–4
pivotFLOAT0.1800.001–4
shadowsFLOAT0.00-2–2
highlightsFLOAT0.00-2–2
saturationFLOAT1.000–3
vibranceFLOAT0.00-2–2
hue_shiftFLOAT0-180–180
false_colorBOOLEANfalse
auto_exposureoptBOOLEANfalse
auto_exposure_lockoptBOOLEANfalse
auto_exposure_evoptFLOAT0.00-10–10
matrix_rroptFLOAT1.00-2–2
matrix_rgoptFLOAT0.00-2–2
matrix_rboptFLOAT0.00-2–2
matrix_groptFLOAT0.00-2–2
matrix_ggoptFLOAT1.00-2–2
matrix_gboptFLOAT0.00-2–2
matrix_broptFLOAT0.00-2–2
matrix_bgoptFLOAT0.00-2–2
matrix_bboptFLOAT1.00-2–2
densityoptFLOAT0.00-2–2
black_liftoptFLOAT0.000-0.25–0.25
shadow_tone_roptFLOAT0.000-0.25–0.25
shadow_tone_goptFLOAT0.000-0.25–0.25
shadow_tone_boptFLOAT0.000-0.25–0.25
highlight_tone_roptFLOAT0.000-0.25–0.25
highlight_tone_goptFLOAT0.000-0.25–0.25
highlight_tone_boptFLOAT0.000-0.25–0.25
tone_balanceoptFLOAT0.500–1

Outputs (2)

NameTypeDescription
graded_displayIMAGE
graded_linearIMAGE