Nodes/comfyui-obvpm/Load Images & Compose (obvpm)
ComfyUI Node

Load Images & Compose (obvpm)

Four reference images, one wire, and no invented pixels

By chanon·Created about a month ago·Updated a day ago· 42
Load Images & Compose (obvpm)
    • image
    layers[]
    max_megapixels1.00
    gap0
    backgroundblack

    Multi-reference work in ComfyUI usually looks like this: four Load Image nodes, four crop nodes, four resize nodes set to match, an Image Stitch to glue them together, and a permanent question about whether the sheet is the size the model expects. Reference-to-video and identity-transfer workflows have made this worse, not better - modern models take a sheet of references, and a sheet is exactly what you don't want to assemble by hand every run.

    Load Images & Compose (obvpm) is that whole stack in one node. It loads several images as layers, gives each one its own crop, and composes them into a single image within a megapixel budget. The layer strip is on the left of the node, the main view on the right, and the composition itself is the first entry in the strip.

    Building the sheet

    Add images with the + add image button, the add dropdown (a live listing of your input folder, subfolders included), by dropping files onto the node, or by pasting from the clipboard with the node selected. Each becomes a layer; a file already in the input folder gets referenced in place rather than copied. Cards dragged in from the Artius browser work too.

    Select a layer by clicking it, delete it with the ✕ badge, drag to reorder. Each layer keeps its own crop and its own aspect lock - the same editor as Load Image & Crop: drag to draw, drag inside to move, drag a corner to resize, click outside to clear. Per-layer ratios are independent, free by default. There's a duplicate button that inserts a copy of the selected layer right after it.

    The info line under the view is where the node earns its keep. It reads something like 4 layers → 1104 × 928 · 0.98 MP · 92% filled · 57% of source - the composed size, how much of the sheet is actually image, the single scale factor applied to everything, and how much of the source resolution you kept. You know what you're about to feed the model before you queue.

    Settings

    • max_megapixels - the largest the composed image may be; 1.0 means 1024×1024. Default 1.0. Sides are rounded to a multiple of 16.
    • gap - pixels of background between layers. 0 puts them flush; a few pixels genuinely helps a model tell one reference from the next.
    • background - black, grey or white, seen in the gaps and in the small margin left by rounding.

    One output: image, the composed sheet.

    The design decision that matters: it's a cap, not a target

    This is the part to understand, because it's where this node differs from a generic image-stitcher, and it's why the results look right.

    Every layer is scaled by the same factor, and none is ever enlarged. A 300×200 crop next to a 3000×2000 one comes out nine times smaller in area - because it is nine times smaller. A small crop cannot take space from a large one by being stretched to fill a slot. So four 256×256 images compose to a 512×512 sheet no matter how big max_megapixels is, since enlarging them would be inventing pixels that were never in your references. Set max_megapixels to 0 and there's no cap at all: every layer at its own size.

    Nothing is ever rotated. A texture-atlas packer would happily take a quarter-turn to fill a gap; a rotated reference is a wrong reference, so this doesn't.

    Your order is the answer. The packer sweeps 48 candidate sheet widths and four placement orders - your layer order, then tallest-first, widest-first and largest-first. Your order wins by default and is only displaced by an ordering that packs at least three points tighter, so dragging layers around still means something. The info line tells you which order was actually used.

    That combination is a stronger guarantee than it looks: order preserved, aspect ratios exact, relative sizes honest. If you're feeding a reference-conditioned model, that's the difference between a sheet that encodes "subject is small in frame" and one that silently says the opposite.

    Install

    ComfyUI Manager → search comfyui-obvpm, or:

    cd ComfyUI/custom_nodes
    git clone https://github.com/chanon/comfyui-obvpm
    

    Restart ComfyUI. It's under obvpm/image, and a node-menu search for obvpm lists the pack. No Python dependencies, no models. The pack's author has a walkthrough video for this node (Load Images & Compose on YouTube) if you'd rather watch it once than read it.

    Gotchas

    layers is managed by the editor - don't hand-edit it. Changing any crop, or swapping the file behind a layer, re-executes the node on the next run, so a re-crop does cost a downstream re-run. And if your sheet comes out smaller than you expected, that's the cap-not-target rule doing its job: a budget of 2 MP doesn't mean you should expect 2 MP out of small crops.

    Categoryobvpm/image

    Inputs (4)

    NameTypeDefaultDescription
    layersSTRING[]Managed by the layer editor on the node — no need to edit by hand.
    max_megapixelsFLOAT1.000–128Largest the composed image may be (1.0 = 1024x1024 pixels). A CAP, not a target: every layer is scaled by one shared factor and none is ever enlarged, so a sheet of small images comes out small rather than being blown up to fill this. 0 = no cap: every layer at its own size (in fill sizing, a sheet of the sources' total area). Sides are rounded to a multiple of 16.
    gapINT00–256Pixels of background between layers. 0 puts them flush against each other; a few pixels helps a model tell one reference from the next.
    backgroundCOMBOblackColour behind the layers — seen in the gaps, and in the up-to-16-pixel margin left by rounding.

    Outputs (1)

    NameTypeDescription
    imageIMAGEThe composed sheet, one image containing every layer.