ComfyUI-LoadImagePath
A ComfyUI extension with 2 custom nodes.
ComfyUI-LoadImagePath
Load images from a pasted path instead of hunting through a file picker — without giving up the mask editor, inpainting, or anything else the built-in nodes do.
Most path-loading nodes replace the built-in loader, and quietly lose things in
the process. The mask editor is the clearest example: it refuses to open on a
node with no imgs, and writes its result back into a widget it finds by the
literal name image. A node that merely looks like a loader satisfies
neither, so inpainting stops working and it isn't obvious why.
So this doesn't replace the loader. Load Image From Path is the built-in
Load Image, with one extra box: paste a path, and the file is imported into
your input folder and selected. From that point everything downstream is core's
own code — the thumbnail, the mask editor, clipspace, inpainting — because the
node is structurally identical to the one those features were written for.
Load Image Sequence From Path covers what the first node deliberately doesn't: a whole folder, loaded in place with no copying, with frame selection.
Nodes
Load Image From Path (category: image)
| Input | Default | Notes |
|---|---|---|
| paste path | — | Paste a path and press Enter. The file is imported into input/ and selected below. Not a graph input — it does its job and clears itself. |
| image | — | The built-in image combo, with its upload button. Identical to Load Image. |
Outputs IMAGE and MASK. Right-click → Open in MaskEditor works, because
this node is a native loader in every respect that matters.
Imports are content-addressed: the filename gets a short hash of the file's
contents, so pasting the same path twice reuses the one copy instead of filling
input/ with duplicates.
Load Image Sequence From Path (category: image)
| Input | Default | Notes |
|---|---|---|
| path | — | Path to a folder of images, or to a single animated file. Folders load every image inside, sorted by filename, as one batch. Subfolders are not searched. Surrounding quotes, a file:// prefix and a leading ~ are accepted. |
| start_index (advanced) | 0 | Skip this many images — or frames, for a single animated file. |
| count (advanced) | 0 | How many to load. 0 means all. |
| select_every_nth (advanced) | 1 | Load only every Nth. |
| threads (advanced) | 0 | Decoder threads. 0 = auto, min(8, CPU count). |
Outputs IMAGE and MASK, and previews the first frame after running. Nothing
is copied. Selection is applied as start, then stride, then cap — the same order
VideoHelperSuite uses, so the same three numbers pick the same frames.
Folders sort lexicographically, so zero-pad your filenames: frame_0010.png
sorts after frame_0009.png, but frame10.png sorts before frame9.png.
Performance
Folder loads decode in parallel. PyAV releases the GIL while decoding, so this scales with cores. 24 PNGs at 1920x1080, 69 MiB total, best of three:
| threads | total | per file | speedup | |---|---:|---:|---:| | 1 | 1.06 s | 44.2 ms | 1.0x | | 2 | 0.60 s | 25.0 ms | 1.8x | | 4 | 0.42 s | 17.3 ms | 2.6x | | 8 (default) | 0.34 s | 14.3 ms | 3.1x | | 16 | 0.31 s | 13.1 ms | 3.4x |
Output is identical regardless of thread count.
Security
The import route copies a file the browser names, off the server's filesystem. That is a real capability, and it is fenced in accordingly:
- Refused when ComfyUI is not on localhost. If
--listenis bound to anything other than a loopback address the route returns 403. SetCOMFYUI_LOADIMAGEPATH_ALLOW_REMOTE=1to override, and only do that if you trust everyone who can reach the server. - The source must really be an image. Its MIME type must be
image/*, anything a browser executes inline (SVG, HTML, XML) is refused, and Pillow has to agree it can parse the header. A renamed.txtor a fake.pngis rejected before a byte is copied, so this cannot be turned into a general file-read. - The destination is never caller-controlled. It is always
input/, with the basename stripped of anything but alphanumerics,-_., plus a content hash, verified withis_within_directory. There is no way to steer the write out ofinput/. - Copies go to a
.partialfile and are then renamed, so an interrupted import cannot leave a truncated file under a name its hash says is complete.
Installation
cd ComfyUI/custom_nodes
git clone https://github.com/dreevelle/ComfyUI-LoadImagePath
No extra dependencies; everything it uses ships with ComfyUI.
Notes
- Equivalence to
Load Imageis verified, not assumed. Both nodes produce bit-identicalIMAGEandMASKtensors against the built-in node for 8-bit RGB, 8-bit RGBA, 16-bit, EXIF-rotated JPEG, a width that is not a multiple of 32, paletted PNG withtRNS, animated GIF, animated WebP, and animated WebP with alpha. - The mask sentinel. No alpha gives a
[B, 64, 64]block of zeros, matching the built-in node — that undersized shape is what downstream nodes read as "no mask". Alpha gives1.0 - alphaat[B, H, W]. - Mixed alpha in one folder is the single case that cannot match the built-in node, since the two shapes above cannot be concatenated. Files without alpha contribute image-sized zeros, which is what the built-in node produces for an all-opaque alpha channel. Nothing is masked either way.
- Mixed sizes raise an error naming both files and both dimensions. Neither node resizes.
- Only the loader needs the frontend extension in
web/. If it fails to load you get a plain native image picker — you lose the paste box, not the node. The sequence node has no frontend code at all. - Recognized extensions come from the same MIME lookup
Load Imageuses: png, jpg, jpeg, webp, gif, bmp, tif, tiff, avif, heic. Not exr, jxl, tga, dds or psd. - Cache invalidation. The loader content-hashes its file, matching the built-in node. The sequence node uses path, size and mtime instead — hashing a 500-frame folder would mean gigabytes of reads on every queue press. The tradeoff is that an edit preserving both size and mtime is not noticed; touching the file forces a reload.
- Memory. Images are float32, so 500 frames at 1920x1080 is roughly 12 GB.
Migrating from VideoHelperSuite
| VideoHelperSuite | Here |
|---|---|
| Load Image (Path) | Load Image From Path, paste into the box |
| Load Images (Path) | Load Image Sequence From Path |
| skip_first_images | start_index |
| image_load_cap | count |
| select_every_nth | select_every_nth |
| frame_count output | core Get Image Size, which returns batch_size |
Behavioural differences worth knowing:
- VHS resized mismatched frames to the most common size in the folder, with a lanczos filter and a centre crop, silently. These raise instead.
- VHS decoded through Pillow, which truncates 16-bit PNGs to 8-bit.
- VHS decided alpha handling once per directory, so one RGBA file changed the channel path for every image in it. These decide per file.
- VHS's path loader did not give you the mask editor. This one does, by not replacing the built-in loader in the first place.