Save Latent EXR
Preserve the exact latent, not a lossy decode
- samples
Here's a fact most people only learn the hard way: the image you see is not what the model produced. The diffusion model works in a compressed latent space, and the VAE decode into pixels is a lossy step that discards information every time. SaveLatentEXR is the node that says "screw the decode, give me the latent itself" - it writes the raw 4-channel latent tensor as an RGBA 32-bit EXR.
Why would you want that? A few genuinely good reasons:
- Exact round-trips. Save a latent, load it back, and you're at the precise state you saved - no encode/decode drift, no quantization. That matters when you're doing multi-pass work and want identical results.
- Batch processing without the VAE. Process latents in bulk and let the pixels happen later, on your schedule.
- Debugging. If you suspect the VAE is the thing eating your detail, this is how you look at what the sampler actually made.
The caveat that shapes everything: this is a 4-channel (SD 1.5 / SDXL) tool. The code reorders and writes four channels; load it back and it assumes four. Flux latents are 16 channels, and this node will cheerfully drop twelve of them on save. Check your model before you use it.
How it works
Latents arrive as (batch, 4, H, W) tensors. The node moves them to (batch, H, W, 4), reorders the channels for OpenCV's BGR layout, and writes each sample as a 32-bit float RGBA EXR with version and frame numbering - name_v001.1001.exr, exactly like SaveEXR. Values aren't clamped or quantized, which is the entire point: latent values live roughly around zero, go negative, and carry fractional precision. Only a float format can hold that honestly.
Since you can't actually see a latent, the README throws in a formula to approximate the RGB you'd get out of the four channels if you want to preview it in a viewer:
r = (0.298*r + 0.187*g - 0.187*b - 0.184*a) * 0.18215
g = (0.207*r + 0.286*g + 0.189*b - 0.271*a) * 0.18215
b = (0.208*r + 0.173*g + 0.264*b - 0.473*a) * 0.18215
(The 0.18215 is the SD VAE's latent scaling factor - it's how you map latent values back to something pixel-like.) Note it's a cheap approximation, the author's words, not a true decode.
Inputs
samples (a LATENT), filename_prefix, version (default 1; -1 drops the version string), start_frame, and frame_pad. Nothing else. It's a pure output node with the same overwrite protection as SaveEXR - existing file means it raises, so bump the version on reruns.
Install
It's in spacepxl's ComfyUI-HQ-Image-Save pack: ComfyUI Manager → search ComfyUI-HQ-Image-Save → install → restart, or git clone https://github.com/spacepxl/ComfyUI-HQ-Image-Save into custom_nodes/. Just imageio and opencv-python, no models.
Read it back with the pack's LoadLatentEXR - same channel convention, so the pair round-trips cleanly. And if you're archiving exact generation state, pair it with --fp32-vae: decode accuracy is only as good as the last lossy step, and fp32 keeps that step honest.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| samples | LATENT | — | |
| filename_prefix | STRING | ComfyUI | — |
| version | INT | 1-1–999 | — |
| start_frame | INT | 10010–99999999 | — |
| frame_pad | INT | 41–8 | — |
Outputs (0)
No outputs