Nodes/comfyui-jz/jz Composite Back
ComfyUI Node

jz Composite Back

Stitch the Original Back Without the Seam

By j-zhang19·Created 28 days ago·Updated 12 days ago· 2
jz Composite Back
  • generated_image
  • original_image
  • image
  • outpaint_mask
  • paste_mask
pad_left0
pad_top0
pad_right0
pad_bottom0
expand4
max_filter_size3
blur_radius4

Gemini Composite is the glue step in a Gemini / "Nano Banana" outpainting workflow. It's the node that answers the question every outpaint ends with: I've got the AI's extended version, now how do I keep my original pixels and lose the visible rectangle where the two meet?

The name is honest about the shape of the problem. Gemini image models (Nano Banana Pro, Gemini 3 Pro Image) are brilliant at filling borders, but the Gemini API has no true mask input like a local inpaint model - you pad the canvas, the model paints the whole thing, and the original content comes back slightly reimagined. The clean way to do outpainting with these models is therefore a pad-and-stitch pattern: pad to a supported API size, let Gemini fill it, then paste your original back on top so nothing inside the original frame changes. This node is that paste, and it does it with a feathered edge instead of a hard cut.

How it works

Mechanically it's simple and you can see all of it in the source. It builds a grayscale mask (white = padded area, black = your original), dilates that mask a few pixels into the original so the feather starts a little inside your image, blurs it for a soft gradient, then inverts it and uses it as the alpha to paste your original over Gemini's output at the pad offsets. The result: near the boundary, your original pixels show through with partial opacity over the AI fill, which is exactly what kills the "I can see where the composite happened" tell.

The inputs that matter

  • generated_image - Gemini's outpainted output (from GeminiImageGenerate).
  • original_image - your pre-outpaint image, unchanged.
  • pad_left / pad_top / pad_right / pad_bottom - wire these straight from GeminiPadCalculator's pad outputs. Getting these right is the whole game: if they don't match the padding the generate call actually used, your original lands in the wrong spot.
  • expand (default 4) - how far the feather grows into your original. Higher = the composite eats more of the AI's border blend.
  • blur_radius (default 4) - Gaussian blur on the mask. Set 0 if you want a hard edge for some reason.
  • max_filter_size (default 3) - the dilate kernel size. Slider steps by 2 because the kernel must be odd; the code enforces that anyway, so don't stress about it.

The defaults are sane. The only things you'll realistically touch are expand and blur_radius, and only if you're seeing a seam.

Outputs

image is the finished composite - that's your Save Image target. outpaint_mask and paste_mask are grayscale debug outputs (white = filled area, and the inverted feathered mask respectively). They're genuinely useful the first time: if something looks wrong, view these to see what the node thinks is padded versus original.

Install

The pack has no requirements.txt and depends on scipy at import time - if scipy is missing, none of its nodes register. So install is:

# ComfyUI Manager → search "ComfyUI-Outpainting-Gemini" is easiest
cd ComfyUI/custom_nodes
git clone https://github.com/jzhang-POP/ComfyUI-Outpainting-Gemini
# only if scipy isn't already in your ComfyUI venv (it often isn't):
source ../venv/bin/activate && pip install scipy

Then restart ComfyUI. Watch out: the pack README's own install line points at a YOUR_USERNAME/Vermeer-Gemini.git placeholder URL - that's a typo, the real repo is jzhang-POP/ComfyUI-Outpainting-Gemini.

Troubleshooting

  • A hard rectangle visible around your original → the feather is too weak or the mask is off; bump expand and blur_radius.
  • Your original is offset / the composite doesn't line up → pad values and the API call disagree. This is the classic one: you set an aspect ratio and resolution manually on GeminiImageGenerate, but the calculator resolved different ones. Wire the calculator's resolved aspect_ratio and resolution outputs into the generate node so the padding and the API size always match.
  • The node doesn't show up at all → check scipy (see install), then reload.

This is a small node that does one job well. Once your padding is wired from the calculator, it's set-and-forget - which is how you want the seam-removal step of an outpainting pipeline to feel.

Categoryjz/image

Inputs (9)

NameTypeDefaultDescription
generated_imageIMAGE
original_imageIMAGE
pad_leftINT0
pad_topINT0
pad_rightINT0
pad_bottomINT0
expandINT40–64
max_filter_sizeINT33–15
blur_radiusINT40–64

Outputs (3)

NameTypeDescription
imageIMAGE
outpaint_maskIMAGE
paste_maskIMAGE