Simple Image Saver
Atomic PNGs, optional 16-bit, no half-written files
- images
What it's for
ComfyUI's stock SaveImage is fine until it isn't. It names files ComfyUI_00001_.png, dumps everything in output/, and has no concept of a 16-bit intermediate. This is the pack's replacement: a saver with a real filename, an explicit format, optional 16-bit PNG, and - the part I actually care about - atomic writes, so a crash or a cancel mid-encode doesn't leave a truncated PNG sitting in your output folder looking like a valid file.
It's an output node. It has no graph output sockets at all, so nothing downstream can consume it; it exists to write files and supply ComfyUI's saved-image preview.
How it works
The core mechanics:
- Atomic publication. The image is encoded to a temporary location and only moved into place once the file is complete. "Publish only complete files" is the engine's contract, and it's why you'll stop finding 0-byte or half-decoded PNGs after a failed run.
unique_filenames(on by default) appends a counter rather than overwriting an existing name. Turn it off only when you genuinely want a stable filename that gets replaced.- Batch handling. A batch of images gets an index in the filename; they don't all land on one name.
- Missing directories are created. Point
output_pathsomewhere that doesn't exist yet and it'll make it.
Inputs worth setting
Required: images, output_path, filename, suffix, file_format, jpeg_quality, include_metadata, unique_filenames. Plus two optional widgets.
output_path takes an absolute path, or a relative one resolved under ComfyUI/output; blank keeps the default. filename is the base name without an extension, and suffix gets appended with a dash when you supply it - handy for keeping a finishing variant next to its source (photo- + final).
file_format is PNG or JPG; jpeg_quality (default 95) is ignored for PNG. Two optional widgets matter for real photo work:
png_bit_depth-8-bit(default) or16-bit. The 16-bit option preserves more of the float image's precision, which is the correct choice for an intermediate you're going to keep editing, and a questionable one for a file you're about to upload anywhere. JPEG stays 8-bit.jpeg_alpha_background-WhiteorBlack, used to composite RGBA before JPEG encoding. PNG keeps its alpha channel instead.
Metadata, and the one thing to check
include_metadata is on by default and writes the workflow prompt and extras into the file, so a saved PNG still drags back into ComfyUI as a loadable graph. Two caveats from the docs, both real. A JPEG's metadata goes in as a comment rather than EXIF, and overly large comments are skipped - so on a big workflow, a JPEG may quietly lose its metadata where a PNG wouldn't. And the server-side --disable-metadata flag overrides the widget entirely, which is why "this saver doesn't write metadata" is sometimes a global setting, not a node bug.
If you upload to CivitAI and care about automatic model/LoRA linking, note that model auto-linking keys on an A1111-style flat parameters block, and the docs here describe workflow prompt/extras. PNG also isn't the format to publish if you're worried about leaking your prompt graph - that's the classic trade in this layer: the graph is the shareable project file, and it's also a full disclosure of your prompt, seed and checkpoints. Keep the PNG as your master, publish a derivative.
Where people get burned
Assuming this replaces SaveImage everywhere. It doesn't have to - it's an output node either way, so the cache still works backward from it and it runs every time. The difference is naming, format control and atomicity.
Two practical gotchas: the node writes no filepath output, so don't try to wire a path to anything downstream; and if you set unique_filenames off, a re-run overwrites the previous file rather than erroring, which is exactly what you asked for and exactly as surprising as it sounds.
Install
ComfyUI Manager → search PortraitUtils (publisher heyburns, GPLv3), or:
cd ComfyUI/custom_nodes
git clone https://github.com/heyburns/PortraitUtils
/path/to/ComfyUI/venv/bin/python -m pip install -r PortraitUtils/requirements.txt
PNG16 I/O goes through OpenCV, so opencv-python-headless>=4.10.0.84 matters here - and install only one OpenCV wheel variant in ComfyUI's Python environment. Along with numpy, Pillow and tifffile, that's the whole dependency list. Restart the ComfyUI server after installing.
Inputs (10)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | — | |
| output_path | STRING | Directory path (absolute or relative to ComfyUI/output). | |
| filename | STRING | ComfyUI | Base filename without extension. |
| suffix | STRING | Optional suffix appended with a dash when provided. | |
| file_format | COMBO | PNG | 2 options: PNG, JPG |
| jpeg_quality | INT | 950–100 | JPEG quality (0-100). |
| include_metadata | BOOLEAN | true | Include workflow metadata (prompt + extras). |
| unique_filenames | BOOLEAN | true | Append a counter to avoid overwriting existing files. |
| png_bit_depthopt | COMBO | 8-bit | 16-bit PNG preserves more of the float image's precision. JPEG remains 8-bit. |
| jpeg_alpha_backgroundopt | COMBO | White | Composite RGBA on this background for JPEG; PNG retains alpha. |
Outputs (0)
No outputs