Rei-ImageStitch
Stitch images in ComfyUI with Rei-ImageStitch
- image_1
- image_2
- image_3
- image_4
- image_5
- image_6
- image_7
- image_8
- image_9
- image_10
- IMAGE
You know the workflow: you've generated four takes of the same prompt, or you want a clean before/after, or you're comparing two upscalers on the same crop. ComfyUI has no built-in "put these images side by side" node, so you either drag them out of the graph and glue them in an editor, or you bolt on a heavy grid/contact-sheet pack. Rei-ImageStitch is the third option: a single node from the small ComfyUI-ReiyaNodes pack that takes 2–10 images and lays them out horizontally.
The name is honest - that's the whole job. It stitches left-to-right only, one row, no rows-and-columns grid magic. If you want an actual contact sheet you should look elsewhere; if you want a comparison strip in seconds without leaving the graph, this is the one.
How it actually works
The Python side is refreshingly small. You feed in image_1 plus as many of image_2 through image_10 as you need, and the node does four things before the final torch.cat along the width:
- Batch matching. Images come in as tensors shaped
B, H, W, C, whereBis the batch size. If your inputs have different batch counts, it pads the smaller ones by repeating the last frame until every batch matches the largest. - Size matching (only when
match_image_sizeis on). Everything is resized to the height of the first image, preserving aspect ratio, using Lanczos resampling - the same non-generative, no-hallucination pixel path the upscaling docs call the honest cheap rung. - Channel padding. If one image is RGB and another RGBA, the RGB one gets an alpha channel (padded with 1.0, so fully opaque) rather than a crash.
- Concatenation. Straight across the width:
image_1 | image_2 | image_3 | ....
All of that happens on the same device as the input tensors, so there's no GPU/CPU copying drama.
The inputs that matter
You'll touch three things and ignore the rest:
num_images(INT, default 3, range 2–10) - how many slots to show. This one's a widget, and the frontend JS adds or removes input sockets to match, right on the graph. No digging through a config.match_image_size(BOOLEAN, defaulttrue) - keep it on unless you've already normalized heights yourself.image_1(required) plus the optionalimage_2…image_10sockets. The node expects them filled contiguously: if you leaveimage_3dangling but connectimage_4, it stops collecting at the first gap. Setnum_imagesto what you're actually feeding, not what you plan to.
The single output is one IMAGE tensor, ready to wire into a VAE Decode → Save/Preview chain or straight into any other image-processing node. It's not an output node, so it does nothing until you connect it to something that saves or displays.
Installing it
It's a two-file pack with zero Python dependencies beyond ComfyUI and PyTorch - no requirements.txt, no model downloads, nothing to fetch. The whole pack is one tiny node plus a UI-only variable node.
cd ComfyUI/custom_nodes
git clone https://github.com/FemReiyaDev/ComfyUI-ReiyaNodes.git
Restart ComfyUI. Or, if you use ComfyUI Manager, just search "ReiyaNodes" and install it there. Either way you're done in under a minute.
Where people get burned
A few real quirks from the code, so you don't discover them the slow way:
- Change
num_imagesand your wiring dies. When the JS removes an input socket, it also disconnects anything plugged into it. Crank the value up to add slots, or down to clean up, and be ready to re-plug your image sources. match_image_sizeoff is a footgun. With it disabled, the node does no resizing - so any height mismatch makes the width concatenation throw a tensor-size error. Turn it off only when every input is already the same height.- Fewer than two images is a silent passthrough. If only
image_1gets connected, the node just hands it back unstitched. That's by design, but it means a broken workflow won't necessarily error - you get one image instead of two. - It only speaks
IMAGE. Masks and latents won't plug in; decode to pixels first.
Is this the most glamorous node in your graph? No. But for "I need this comparison strip before my coffee finishes brewing," it does exactly one thing and does it without a 200MB dependency. Sometimes the right tool is the boring one.
Inputs (12)
| Name | Type | Default | Description |
|---|---|---|---|
| num_images | INT | 32–10 | — |
| match_image_size | BOOLEAN | true | — |
| image_1 | IMAGE | — | |
| image_2opt | IMAGE | — | |
| image_3opt | IMAGE | — | |
| image_4opt | IMAGE | — | |
| image_5opt | IMAGE | — | |
| image_6opt | IMAGE | — | |
| image_7opt | IMAGE | — | |
| image_8opt | IMAGE | — | |
| image_9opt | IMAGE | — | |
| image_10opt | IMAGE | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |