Nodes/comfyui-vae-float32/ANDRO Save EXR
ComfyUI Node

ANDRO Save EXR

Real float32 EXR out of ComfyUI — with the file that tells you how it was made

By AndreiOrehov·Created 28 days ago·Updated about 18 hours ago· 4
ANDRO Save EXR
  • images
  • folder
filename_prefixfloat32/frame
half_floatfalse
output_folder
write_metadatatrue
decode_report
clipped_layerfalse
colorspacesrgb_display
colorspace_note
start_frame1
padding5
shot_info
embed_workflowtrue

ANDRO Save EXR is where the float32 decode in this pack actually lands. It writes an IMAGE batch as a real float32 EXR sequence, values untouched - including everything outside [0,1] - and it's the only sane target for keep_out_of_range decodes that are headed into a grade. Wire ANDRO VAE Decode in, save, and out come frame.00001.exr files that carry the headroom a colourist actually spends. The pack's own arithmetic: 121 frames of 1280×704 float32 EXR is about 1.2 GB, so give it a folder of its own.

It uses the OpenEXR module, not cv2, and verifies the file landed rather than trusting the writer - both deliberate. OpenCV compiles the EXR codec in but leaves it disabled unless OPENCV_IO_ENABLE_OPENEXR=1 is set before cv2 imports, which no ComfyUI launcher does. Any node writing EXR through cv2.imwrite silently produces nothing; this one sidesteps the whole class of bug. No EXR backend available? It falls back to a 32-bit float TIFF carrying the same values under a different extension (needs pip install OpenEXR to avoid the fallback).

The part no other save node does

The header records how its own pixels were made. With write_metadata on, each file carries andro/* attributes - measured range, how much sat outside [0,1], bit depth, frame count - and wiring ANDRO VAE Decode's range_report into the decode_report input stores the decode's own account verbatim, dtypes included. Six months later the file still answers "was this the float32 pass?" on its own. That's the workflow-in-the-file philosophy ComfyUI PNGs made famous, transplanted to a format that can hold out-of-range values.

  • colorspace (default srgb_display) labels what the numbers are: a decoded SDR frame is display-referred sRGB/Rec.709 gamma, not linear, which is what most compositors would wrongly assume about an untagged EXR. Two exceptions to remember: LTX-2.5 HDR decodes are ACEScct, and the LTX-2.3 HDR IC-LoRA is LogC3. This is a label, not a conversion - not one pixel is touched. Nuke or Resolve still has to be told the same colourspace on input.
  • clipped_layer adds a second EXR layer holding exactly what the stock clamp would have deleted, zero everywhere it would have kept the value. The loss then travels inside the file instead of in a screenshot you have to show someone.
  • start_frame/padding - defaults 1 and 5 give the historic stem.00001.exr; VFX pipelines set 1001 with padding 4 and land on frame.1001.exr, the convention Nuke and Resolve expect. Numbers too big for the padding are written in full, never truncated (truncation would collide two frames onto one filename).
  • embed_workflow (on by default) stores the whole workflow and prompt in the header plus a summary of every checkpoint, VAE, seed and prompt - turn it off for confidential graphs; the summary fields still get written. A <stem>.manifest.json sidecar carries the same facts for scripts without an EXR library.
  • output_folder - absolute path to drop the sequence straight into a project folder; empty means the ComfyUI output directory.

half_float (16f) halves file size at roughly 11 bits of mantissa - far above bf16, so a 16f EXR of a float32 decode keeps most of what the decode won. Use 32f when frames will be stretched hard under a grade.

Install

ANDRO Save EXR ships in the comfyui-vae-float32 pack. ComfyUI-Manager → search comfyui-vae-float32 → install → restart, or:

cd ComfyUI/custom_nodes
git clone https://github.com/AndreiOrehov/comfyui-vae-float32
pip install OpenEXR

Restart and find it under ANDRO. One operational gotcha shared across the pack: a measuring/saving node that "never runs" usually means you hit the selection strip's ▶ button, which executes only the selected output node and drops everything else while still reporting success. Hit a plain Run. The author's full pipeline example, LTX2.5_float32_EXR.json, shows the intended whole - float32 decode, EXR sequence, video, and the decode's range report all from one image.

CategoryANDRO

Inputs (13)

NameTypeDefaultDescription
imagesIMAGEThe batch to write. Values are written exactly as they arrive - nothing is clamped, scaled or tone-mapped on the way out.
filename_prefixSTRINGfloat32/frameSubfolder and file stem. Frames are numbered from 1 as stem.00001.exr, so 'float32/frame' gives float32/frame.00001.exr.
half_floatBOOLEANfalse16f halves the file size and still carries everything outside [0,1] - what it costs is precision, roughly 11 bits of mantissa against 24. That is far above bfloat16, so a 16f EXR of a float32 decode keeps most of what the decode won. Use 32f when the frames are going into a grade that will stretch them hard, 16f when disk or a downstream tool argues.
output_folderoptSTRINGAbsolute path to write to, e.g. D:/renders/shot_04. Empty means the ComfyUI output directory. Use this to drop a sequence straight into a project folder instead of fishing it out of output/ later; filename_prefix still applies inside it.
write_metadataoptBOOLEANtrueRecord how these pixels were made in the EXR header: measured range, how much sat outside [0,1], bit depth, and - if you wire the decode report in - the dtypes the decode actually ran in. Six months later the file still answers 'was this the float32 pass?' on its own. Needs the OpenEXR backend; the TIFF fallback drops it.
decode_reportoptSTRINGWire ANDRO VAE Decode's range_report here and its contents are stored in the file's header. Optional - without it the metadata still carries everything measurable from the pixels themselves.
clipped_layeroptBOOLEANfalseAdd a second EXR layer named 'clipped' holding exactly what the stock [0,1] clamp would have deleted - zero everywhere it would have kept the value. The evidence then travels inside the file instead of in a screenshot. Costs roughly double the file size, and readers that ignore extra layers are unaffected.
colorspaceoptCOMBOsrgb_displayWhat these pixels ARE, written into the header. A decoded SDR generation is display-referred sRGB/Rec.709 gamma, not linear - that is what most VAEs produce (SD, Flux, Wan, LTX SDR), so srgb_display is the honest default. Two exceptions: LTX-2.5 HDR decodes are ACEScct, and the LTX-2.3 HDR IC-LoRA is LogC3. This writes a label - no pixel is converted.
colorspace_noteoptSTRINGFree text appended to the label, e.g. 'Flux.2 decode' or 'after OCIO ColorSpace to ACEScg'.
start_frameoptINT10–999999Number the first frame gets. 1 keeps the historic stem.00001.exr; VFX pipelines start a sequence at 1001.
paddingoptINT51–8Digits in the frame number: 5 gives shot.00001.exr, and 4 with start_frame 1001 gives shot.1001.exr. A number too large for the padding is written in full rather than truncated.
shot_infooptSTRINGProject / shot / artist / note. Free text; it goes into the EXR header as andro/shotInfo and into the manifest beside it.
embed_workflowoptBOOLEANtrueStore the full workflow graph in the EXR header and in the sidecar manifest, so the file can rebuild the run that made it. Turn it off for confidential graphs - the summary fields (models, seeds, prompts, API settings, hash) are still written.

Outputs (1)

NameTypeDescription
folderSTRINGThe folder actually written to - wire it onward to a node that reads the sequence back.