Nodes/ComfyUI_Swwan/Image Pad For Outpaint Masked (Swwan)
ComfyUI Node

Image Pad For Outpaint Masked (Swwan)

Grow the canvas and get the mask to fill it

By aining2022·Created 10 months ago·Updated about 18 hours ago· 33
Image Pad For Outpaint Masked (Swwan)
  • image
  • mask
  • IMAGE
  • MASK
◄left0►
◄top0►
◄right0►
◄bottom0►
◄feathering0►

Outpainting is the one job masked inpainting still owns outright. Instruction-editing models will happily change a garment from a sentence, but "extend this frame 400 pixels to the left and keep everything else bit-identical" is a mask operation, and it starts with a canvas that doesn't exist yet.

This node builds it. It's the Swwan copy of ComfyUI core's ImagePadForOutpaint, and it returns the pair you actually need: the padded IMAGE and the MASK that tells the sampler what's new.

Inputs and outputs

Required: image (IMAGE), left, top, right, bottom (INT, default 0, step 8, up to 16384), feathering (INT, default 0, step 1).

Optional: mask (MASK).

Outputs: IMAGE and MASK.

The step-8 on the padding values is not decoration. A VAE downsamples by 8, so padding in multiples of 8 keeps the latent grid aligned with the original pixels. Pad by 7 and you'll be half a latent cell off at the seam - visible as a thin band of mess.

What it produces

The canvas is filled with mid-grey (0.5), and your image is pasted at (left, top). Grey rather than black is deliberate: 0.5 is neutral to a diffusion model and gives the model something to work from instead of a hard black edge.

The mask output depends on whether you wired the optional mask.

No mask in: the output mask is 1 everywhere on the new canvas except over the original image region, which is 0, with a soft feathering ramp at the border between them. In other words, 1 = "generate here." That's the convention the usual outpaint chain wants: pad, VAE-encode, and use the mask to say what's new.

Mask in: the node pads your mask and then inverts it (1 - mask). So a subject mask going in comes out as its complement, with the new canvas area set to 1. That inversion is the part that confuses people - it's there because the downstream inpainting convention is "1 means regenerate," but if you were expecting your mask back out unchanged, you'll get something that looks broken and isn't.

One more safety behavior: if the incoming mask is entirely black, the node prints a warning and treats it as if you'd passed nothing. No error, just a log line and the no-mask path.

The feathering gotcha

feathering is applied by a per-pixel Python loop over the original image's height and width. That means it's slow in absolute terms on a big image, and more importantly: if feathering * 2 is not less than both the image height and the image width, the feathering block is skipped entirely. Set feathering above half your image dimension and the node quietly hands back a hard-edged mask. Not a crash - just a seam you didn't ask for.

Typical values are small. The KB's inpainting guidance suggests 4–12 pixels as a normal range for mask blur; bigger bleeds generated content into the region you were trying to preserve.

Where it fits

The standard chain: load image → this node → VAEEncode (or VAEEncodeForInpaint) with the mask attached as latent noise → KSampler at high denoise → crop the padded canvas back to the original framing. The mask is what keeps the original pixels untouched; the concat-and-crop at the end is what keeps the composition yours.

If you want the target-size version - "make this 1920×1080 regardless of what it is now" - that's the sibling node Image Pad For Outpaint Target Size, which downscales first and then centers.

Install

cd /path/to/ComfyUI/custom_nodes
git clone https://github.com/aining2022/ComfyUI_Swwan.git
cd ComfyUI_Swwan
python -m pip install -r requirements.txt

Windows portable:

.\python_embeded\python.exe -m pip install .\ComfyUI\custom_nodes\ComfyUI_Swwan\requirements.txt

Restart ComfyUI, hard-refresh the browser, search Swwan; it's under Swwan/Advanced/Mask and needs no models - it's a canvas operation, not inference. requirements.txt adds the vision extras the pack uses elsewhere; this node itself only needs the torch you already run.

And the usual pack-level upgrade note: 1.0.0 re-namespaced nodes that overlapped with KJNodes and registers no aliases, so a stale workflow may show a missing node. python scripts/migrate_workflow.py old.json --dry-run from the repo root will show the mapping before it writes anything.

CategorySwwan/Advanced/Mask

Inputs (7)

NameTypeDefaultDescription
imageIMAGE—
leftINT00–16384—
topINT00–16384—
rightINT00–16384—
bottomINT00–16384—
featheringINT00–16384—
maskoptMASK—

Outputs (2)

NameTypeDescription
IMAGEIMAGE—
MASKMASK—