Nodes/Comfyui-Image-Stitch/Multi Stitch Images
ComfyUI Node

Multi Stitch Images

Ctrl+V your whole reference folder into one node

By ssain3d-lgtm·Created 9 days ago·Updated a day ago· 0
Multi Stitch Images
  • images
  • image
  • cells
  • width
  • height
directionright
match_image_sizetrue
spacing_width0
spacing_colorwhite
images_json[]
layout_modestrip
grid_columns3
custom_spacing_color#808080
output_limitnone
output_limit_px2048
grid_cell_width0
grid_cell_height0
output_cellsfalse
cells_resolutionplaced
minimum_image_side0
match_referencesmallest
size_reference1
size_megapixels0.00
size_divisible_by32

ComfyUI's stock Stitch Images node takes two wires and glues them together. With six images you chain three of them and pray. Multi Stitch Images throws that out: click the node, hit Ctrl+V, and every image on your clipboard lands inside it as a card. Drag the cards into order, crop and rotate each one in place, then output one strip or a grid.

Why you'd actually reach for it

Two kinds of work want this. Reference sheets first: a clean 2x2 of a face or a 3x1 of poses, all the same height, nothing stretched, for the multi-image input Qwen-Image-Edit-2509 and later edit models take. Building that in an external editor and re-uploading is the loop this node deletes.

Then contact sheets - eight seeds side by side, or before/after in one frame. There's an IMAGE input too, so results go straight in without saving. Reference-image conditioning is where identity work lives now (character-consistency.md), and that family of models eats collages.

How it works

Pasting uploads the files into ComfyUI/input/multi_stitch/. The workflow stores only references plus your crop, rotation, flip and order - sources are never modified, which is why reordering costs nothing.

On queue the node does a header-only pass: dimensions and EXIF orientation, no pixel decoding, then the exact canvas from its layout maths. It refuses if the result is absurd. Then it allocates the canvas and streams images in one at a time, releasing each - memory is roughly canvas + one source, not the sum of everything you pasted.

In strip mode the others scale to the reference's height (or width, vertically); in grid mode each image fits inside its cell, never stretched. left/up draws the first image last on screen.

The inputs that matter

layout_mode is strip or grid; grid_columns (default 3) sets the grid's width and direction (right/down/left/up) the fill order.

match_image_size is on by default, and match_reference picks what everything matches. smallest (default) shrinks the others to the shortest image, so nothing is ever upscaled. largest enlarges them - softer output, your call. first copies the classic Stitch Images behaviour.

spacing_width and spacing_color set the gaps; that colour also fills the letterbox around a smaller image. output_limit + output_limit_px cap the result's width, height or long side and only ever shrink it. minimum_image_side is the sleeper: the run aborts before decoding if any placed image's short side would fall below it, which is the guard you want when a face is about to become 40 pixels wide.

For the size outputs, size_reference picks which image (1 = the first), size_megapixels rescales it keeping aspect, and size_divisible_by snaps each side to a multiple - 1440x2560 at 0.8 MP and 32 becomes 672x1184.

Everything from output_limit onward hides under Options ▸, except non-default values: those stay visible and get counted in the pill, so nothing changes your output quietly.

Outputs

image is the stitched strip or grid: Preview Image, Save Image, VAE Encode, or straight into an edit model's image input. cells is per-image when output_cells is on - one frame each, centred in a uniform cell with the background colour padding it out, for when another node wants individual references the same shape. cells_resolution picks the placed size or the unscaled original crop; with it off, cells repeats image, so the slot is never dead.

width and height are INTs from the size panel: feed them to an Empty Latent Image and your latent matches your reference's aspect while staying divisible by 32.

Install

No pip install needed. The requirements file has exactly one entry, av, used only for server-side video frame decoding and already shipped with current ComfyUI.

cd ComfyUI/custom_nodes
git clone https://github.com/ssain3d-lgtm/Comfyui-Image-Stitch.git

Restart and look under image/transform → Multi Stitch Images. ComfyUI Manager works by searching the pack title, as does a ZIP install - just don't end up with Comfyui-Image-Stitch/Comfyui-Image-Stitch/. Two example workflows ship with it in the template browser.

Where people get burned

Workflows moved between machines. The images live in that node's input/multi_stitch/ folder, not inside the workflow. On another PC the cards read Missing · click to relink; click one, pick the file, and your crops and order survive.

Hand-editing images_json in the workflow JSON. Don't - it's the hidden string the node's UI writes, and a typo yields corrupted image list in workflow.

The safety guard. Stitching full-resolution photos with match_image_size off trips the 128 MiPixels (~134.2 MP) cap. The error gives the estimated size and float32 footprint before allocating anything. Fixes, best first: match_image_size on, grid, or output_limit. Related: 256 images per node is the ceiling, and the overflow gets skipped with a notice.

A stale frontend after git pull. Most of this node is JavaScript: restart ComfyUI and hit Ctrl+F5.

Video frame capture returning 501. That's the PyAV routes on a slimmed-down ComfyUI: pip install av, restart. The stitch itself never touches PyAV.

Categoryimage/transform

Inputs (20)

NameTypeDefaultDescription
directionCOMBOrightStrip: where each next image goes. Grid: the fill order — right/left fill row by row, down/up fill column by column.
match_image_sizeBOOLEANtrueScale every image to the reference image (match_reference, the smallest by default): its height (or width) in a strip, fitted inside its cell in a grid. Off keeps each image at its own size.
spacing_widthINT00–1024Gap between images in pixels, filled with spacing_color. Odd values work too.
spacing_colorCOMBOwhiteColour of the gaps and of any letterbox area around a smaller image. custom uses custom_spacing_color.
images_jsonSTRING[]The pasted image list with each crop, rotation and flip. Managed by the node's own UI and hidden.
layout_modeCOMBOstripstrip: one row or one column. grid: rows and columns, grid_columns wide.
grid_columnsINT31–16Number of columns in grid mode. The rows follow from the image count.
custom_spacing_colorSTRING#808080Hex colour (#RRGGBB) used when spacing_color is custom. Pick it with the colour button on the node.
output_limitCOMBOnoneScale the finished result down so its width, height or long side is at most output_limit_px. Never scales up. none keeps the native size.
output_limit_pxINT204864–16384Pixel cap used by output_limit.
grid_cell_widthINT00–16384Grid only: fixed cell width in pixels; every image is fitted inside the cell, never stretched. 0 sizes the cells from the largest image.
grid_cell_heightINT00–16384Grid only: fixed cell height in pixels; every image is fitted inside the cell, never stretched. 0 sizes the cells from the largest image.
output_cellsBOOLEANfalseAlso fill the cells output with one frame per image, each centred in a uniform cell, for using the references separately. Off: cells repeats the stitched image.
imagesoptIMAGEOptional IMAGE batch appended after the pasted images, so a generated result can be stitched without saving it first.
cells_resolutionoptCOMBOplacedplaced: each cell at the size the image has in the stitched result. source: at the original cropped size, unscaled.
minimum_image_sideoptINT00–131072Stop before decoding if any placed image's short side would be smaller than this many pixels. 0 turns the check off.
match_referenceoptCOMBOsmallestWhich image the others are scaled to when match_image_size is on. first: the first in the list. largest / smallest: the tallest or shortest image in a horizontal strip (widest or narrowest in a vertical one), the largest or smallest by area in a grid. The reference keeps its own size, so smallest never enlarges anything.
size_referenceoptINT11–256Which image the width and height outputs describe, by its number in the list: 1 = the first, 2 = the second… Frames from the IMAGE input count after the pasted images; a number past the end means the last image. Its size after crop and rotation, rescaled to size_megapixels when that is above 0, with each side snapped to a multiple of size_divisible_by.
size_megapixelsoptFLOAT0.000–64Rescale the width and height outputs to cover this many megapixels, keeping the reference image's aspect ratio. 0 keeps its own pixel count.
size_divisible_byoptINT321–512Snap the width and height outputs to the nearest multiple of this many pixels, never below one multiple. Latents need a multiple of 8; 32 or 64 suits most models.

Outputs (4)

NameTypeDescription
imageIMAGEThe stitched strip or grid.
cellsIMAGEOne frame per image, centred in a uniform cell, when output_cells is on; otherwise the stitched image again.
widthINTWidth of image number size_reference (1 = the first), rescaled to size_megapixels and snapped to size_divisible_by — for an Empty Latent or a resize node downstream.
heightINTHeight of image number size_reference (1 = the first), rescaled to size_megapixels and snapped to size_divisible_by — for an Empty Latent or a resize node downstream.