Nodes/comfyui-exr-plate/Save Plate (linear)
ComfyUI Node

Save Plate (linear)

Where a Nuke roundtrip silently goes wrong

By Samuelsujan·Created 4 days ago·Updated 4 days ago· 7
Save Plate (linear)
  • images
  • alpha
  • written_path
path
first_frame1
custom_width0
custom_height0
format
colorspacesRGB -> linear
bit_depth
send_to_nukefalse
nuke_hosthttp://127.0.0.1:8189

Generating something is the easy half. Getting it back into a comp as a linear EXR that merges cleanly over your plate is the half that eats an afternoon, because ComfyUI's default Save Image writes a PNG with the sRGB-ish values it was handed, and your comp wants linear light. This node is the other end of the roundtrip: it writes EXR (or TIFF/PNG/JPG), applies the inverse colorspace transform on the way out, and keeps float precision and values above 1 when the format allows it.

It's part of Samuelsujan's EXR Plate pack - same author, same premise. Load with keep linear or linear -> sRGB, drive the model, then set this node's colorspace to the inverse of whatever you did on the way in, and what lands on disk is linear again.

How it works

images is a batch, and frame i is written to your numbered path starting at first_frame. The path handling does more work than it looks:

  • The extension always comes from format - path says .png, dropdown says exr, you get .exr. Deliberate: a path wired from the Path Builder can't disagree with the writer.
  • Point it at a bare folder (existing directory, trailing slash, no extension) and it names files itself: plate.####.exr, or plate.exr for a single frame.
  • Multi-frame with no padding in the path gets .#### inserted rather than failing, and missing output directories are created for you.

Per frame: the colorspace transform goes on first, then an optional resize, then a channel flip and the write. EXR goes out half- or full-float with ZIP compression; TIFF and PNG are scalings into the integer range; JPG at quality 95. Wire in alpha and it's resized with the RGB and written as the fourth channel - except JPG, which has no alpha.

And there's send_to_nuke: after the write, the node POSTs the path and frame range to the Nuke-side bridge listener (default http://127.0.0.1:8189) so a Read node with your fresh render appears in the comp. If Nuke isn't up it prints a console warning and the write still succeeds - it will not fail your render over this.

The inputs you'll set

  • path - absolute, with #### for sequences. Wire it from a Path Builder if you don't want to think about versions.
  • format - exr is the one that keeps HDR values above 1. TIFF and PNG are integer formats: everything clamps to 0–1 on write. png (16-bit) gives you precision, not range - a 16-bit staircase inside the same 0–1 window, not a replacement for EXR. JPG throws away alpha and is only useful as a review proxy.
  • colorspace - defaults to sRGB -> linear, and this is the field that quietly breaks things. See below.
  • bit_depth - EXR only, ignored elsewhere. half (16-bit) is plenty for a beauty plate; go float (32-bit) for depth/Z or anything you'll grade hard.
  • custom_width / custom_height - resize on save; set one and the other keeps aspect.
  • alpha, send_to_nuke and nuke_host are the optional ones; leave the last two alone unless you're running the bridge.

The only output is written_path (a STRING - one path, or first .. last (N frames)). It's an output node, so it always runs and the cache works backward from it. There's no image preview from this node, so keep a Preview Image on the branch before it if you want to eyeball the result.

Installing it

Same pack, same one-time setup - ComfyUI Manager → search EXR Plate (Samuelsujan's EXR Plate) → Install, or:

cd ComfyUI/custom_nodes
git clone https://github.com/Samuelsujan/comfyui-exr-plate
python -m pip install -r comfyui-exr-plate/requirements.txt   # opencv-python>=4.6, numpy

Restart ComfyUI and hard-refresh the browser. The pack's web/ folder has to stay a subfolder of the pack - WEB_DIRECTORY = "./web" in __init__.py is what makes ComfyUI serve it.

Where people get burned

  • The double-decode. The most common way to wreck a roundtrip: load with keep linear (tensor is now linear) and save on the default sRGB -> linear. You've applied an sRGB decode to linear data and the plate comes back crushed and contrasty. Rule of thumb: if the loader, the saver and everything in between don't care about colorspace, set both to keep linear. The pack ships a passthrough_api_format.json workflow for exactly this test - Load → Save, keep linear, clamp off - and the check is to Merge (minus) the result against the source in Nuke and gain up. Black frame means a lossless pipeline.
  • Clipping already happened upstream. If the loader's clamp_output was on, no save setting gets the headroom back. That decision lives at the loader.
  • Overwrites. Same path plus same frame range means the second queue silently eats the first render. There's no auto-versioning here - that's the Path Builder's job.
  • Relative paths. Unlike the loader, this node doesn't resolve against ComfyUI's input directory; a relative path lands relative to the ComfyUI process's working directory, which is not where you think. Give it an absolute path.
  • Alpha direction. The alpha input is a plain MASK, and this pack reads and writes the channel as-is (white = opaque), while core Load Image hands out 1 - alpha (white = transparent). If your composite comes back with the matte punched out backwards, that mismatch is why.
  • send_to_nuke doing nothing. It's a urllib call to localhost; if Nuke isn't open with the bridge loaded you get a console line and nothing else. Not an error, just a no-op.
CategoryEXR Plate

Inputs (11)

NameTypeDefaultDescription
imagesIMAGE
pathSTRINGOutput path with #### / %04d for sequences. e.g. /out/END_130_comp.####.exr
first_frameINT10–999999
custom_widthINT00–16384Resize on save. 0 = keep. One value set = keep aspect.
custom_heightINT00–16384
formatCOMBOEXR = float, keeps HDR values above 1. tiff/png/jpg are integer formats: values are clamped to 0-1 on write. jpg has no alpha.
colorspaceCOMBOsRGB -> linearInverse of whatever the load applied, so the plate lands back in linear for Nuke.
bit_depthCOMBOEXR only; ignored for other formats.
alphaoptMASK
send_to_nukeoptBOOLEANfalseAfter writing, push the result to Nuke as a Read node (needs the Samuelsujan bridge listener running in Nuke).
nuke_hostoptSTRINGhttp://127.0.0.1:8189Nuke bridge listener address.

Outputs (1)

NameTypeDescription
written_pathSTRING