ComfyUI Node

DHan-Composite

Paste the edit back and keep every pixel it didn't touch

By DHan315·Created 2 months ago·Updated 22 days ago· 1
DHan-Composite
  • generated_image
  • source_image
  • edit_mask
  • image
  • composite_mask
  • report
  • debug_view
◄mask_modeEdit Mask►
◄change_sensitivity0.20►
◄mask_grow_px0►
◄edge_feather_px12►
◄seam_match0.35►
◄debugfalse►

You asked for one change and got a whole new photograph

Ask Nano Banana, GPT Image, Qwen Image Edit or Flux Kontext to put a leather jacket on someone and it'll do that happily - along with quietly re-rendering the curtains, the background grain, and the exact exposure of every pixel you liked. Instruction editors are whole-frame models wearing a mask-shaped hat.

The one thing a local workflow can do that no edit model will do for you is leave the rest of the frame bit-identical. Composite the changed region back onto the original and nothing outside it moved. That's the standing advice - "PLEASE composite your image after inpainting!" was a +356 post for a reason - and doing it by hand takes a mask combine, a feather, ImageCompositeMasked, and maybe a color match.

DHan-Composite is that chain in one node: source_image, generated_image and a mask in, one frame out where only the masked region is new. It runs no model and calls nothing over the network - the local half of any hosted-editor workflow.

How the paste actually works

Short and deterministic. The pack declares zero dependencies - no OpenCV, SciPy or scikit-image.

  1. The generated image is bilinearly resized to the source canvas, and your edit_mask is thresholded to binary at 0.5 - soft masks get hardened.
  2. In the detection modes it builds a change mask: per-pixel RGB distance between source and generated, against a threshold of 0.025 + 0.20 × change_sensitivity.
  3. mask_mode picks yours, the detected one, or their union, then mask_grow_px dilates the result.
  4. seam_match averages source - generated over an edge ring inside the hard mask and adds that shift back onto the generated pixels there - one mean per image, so it fixes a uniform color offset, not a drifting gradient.
  5. The alpha ramp is a double box blur of the hard mask at edge_feather_px, and the final pixel is source * (1 - alpha) + matched * alpha.

The inputs worth touching

edit_mask is required and always wired, even in Detected Changes mode where its contents are ignored. Drop a core SolidMask at 0 into it and move on.

  • mask_mode - Edit Mask (default, trusts your paint), Edit Mask + Detected Changes (the union), or Detected Changes (no painting).
  • change_sensitivity (0–1, default 0.2) - detection modes only, and the naming reads backwards. Higher is stricter: 0.0 is permissive, 1.0 catches only strong changes. The default threshold works out at 0.065 in RGB, low enough that re-encode noise counts as an edit.
  • mask_grow_px (0–256, default 0) and edge_feather_px (0–256, default 12) - push the region outward when the edit bleeds past your paint, and ramp the blend; 4–12 px is the normal range for a mask seam.
  • seam_match (0–1, default 0.35) - raise it when the patch reads as a different white balance.

Outputs

image is your composite. composite_mask is the binary hard mask (post-grow, pre-feather) - fine for a detailer or MaskToImage, wrong if you wanted a soft edge. report is a text summary for something like PreviewAny, and the fastest way to check which mode actually ran. debug_view is a 2×2 source/generated/mask/result grid when debug is on, and a 1×1 black image when it's off.

Install

Manager, search DHan, or:

cd ComfyUI/custom_nodes
git clone https://github.com/DHan315/Comfyui-DHan-Composite

Restart. That's the whole install - nothing to pip install, no model files. It's one node (DHan-Composite, category DHan/Composite) plus a hidden legacy alias: workflows saved under its old name still load as a deprecated ARCCompositeNode, with identical behavior.

Where people get burned

Detected Changes at the default sensitivity flags everything. At 0.2 you'll often get a full-white mask and a passthrough composite - which looks like the node is broken. Raise change_sensitivity until only your region lights up, or paint the mask and use Edit Mask.

Aspect mismatches get squashed. An editor returning 1024×1024 for your 832×1216 source gives you a horizontally squeezed composite. And uneven batches collapse: if both images arrive batched with different sizes and neither is 1, the node keeps the first frame and repeats it.

A hard line at the edge means less feather and more mask_grow_px. Right shape but wrong light is a color problem: raise seam_match, or use a statistics-based Color Match Image pass if the correction needs to vary across the region.

Node missing after install? With nothing to pip-install, that's usually a path problem - the clone landed in a custom_nodes folder ComfyUI isn't reading. Check the startup log.

Reach for it when

Your edit is almost right - right edit, wrong everything-else - and you want the source preserved. API editors, drifting local editors, a detail pass you want pasted back at original resolution. If the whole image is fair game, skip it.

CategoryDHan/Composite

Inputs (9)

NameTypeDefaultDescription
generated_imageIMAGE—
source_imageIMAGE—
edit_maskMASK—
mask_modeCOMBOEdit Mask3 options: Edit Mask, Edit Mask + Detected Changes, Detected Changes
change_sensitivityFLOAT0.200–1—
mask_grow_pxINT00–256—
edge_feather_pxINT120–256—
seam_matchFLOAT0.350–1—
debugBOOLEANfalse—

Outputs (4)

NameTypeDescription
imageIMAGE—
composite_maskMASK—
reportSTRING—
debug_viewIMAGE—