Composite Masked (Hash-Perfect)
The node that makes 'edit only this part' actually true
- destination
- source
- mask
- IMAGE
Here's the thing nobody warns you about with Qwen-Image-Edit: it doesn't actually edit part of an image. It takes the whole frame into context and emits a whole new image, which means the pixels you asked to leave alone come back "close but not identical." Ask it to change one lamp and the whole room subtly shifts. That's why this pack exists, and this node - Composite Masked (Hash-Perfect) - is the pixel-space guarantee that makes "hash-perfect" a real word.
The name is the promise. Where your mask says keep original, this node copies the original image's pixels over verbatim - no VAE round-trip, no resampling, no float rounding. The non-edited region comes out torch.equal to your source, bit for bit. That is the one thing the model itself can never give you, and it's the same guarantee masked inpainting used to own before instruction-editing models took over the workflow.
How it works
Pure threshold compositing. Every pixel where the mask is >= threshold is taken from the source (your edited image). Every other pixel is copied from the destination (your original). Because the "keep" branch is a straight tensor copy, there's no room for drift to sneak back in.
If you set feather above 0, the node blurs the mask and blends a soft edge instead. Handy when a hard boundary shows, but know the cost: the moment feather is on, the outside region is blended too, and the hash-perfect guarantee is gone. Keep it at 0 if the guarantee is the whole point.
The inputs that matter
- destination - your original source image. Used outside the mask.
- source - the edited image, typically straight off a
VAEDecode. - mask - white = edited region, black = keep original. Optional; if you don't connect it, the node just passes the edited image through.
- threshold - default 0.5. Pixels at or above this mask value count as "edited."
- feather - default 0. The soft-edge trade-off above.
Output is a single IMAGE, ready for a SaveImage or whatever else is downstream. The node also broadcasts batch sizes for you, so a single-frame original and a batched edit just work.
Where it slots into the workflow
It's the finishing move in a two-node combo with Qwen Image Edit+ (Mask) from the same pack. The encoder node hints the model where to edit, and this node enforces the boundary afterwards. Wire: original → destination, VAEDecode output → source, your mask → mask, then save. The pack ships a ready-made "PixelPerfect" workflow doing exactly this.
Installing it
The usual route: ComfyUI Manager → search comfyui_qwen_edit_pixel_perfect → install, restart. Or by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/oron1208/comfyui_qwen_edit_pixel_perfect
Then restart ComfyUI. This node is pure torch - no OpenCV, no extra models to download. One real caveat: the pack is written against ComfyUI's new-style comfy_api.latest / io.Schema node API, so it needs a reasonably recent ComfyUI. If the nodes don't appear after install, update ComfyUI first - that's the fix for most "missing node" confusion with this pack.
Common issues
The classic gotcha is connecting no mask and wondering why nothing changed - you get the edited image back untouched, which is correct behavior. The second is feather: set it, and your "keep original" region is no longer bit-identical, which defeats the node's whole reason to exist. And if the whole frame still looks altered, check that your mask resolution isn't wildly off - the node resizes it to the image with bilinear interpolation, which softens edges slightly even at feather 0.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| destination | IMAGE | Original (source) image. Used outside the mask. | |
| source | IMAGE | Edited image (e.g. VAEDecode output). Used inside the mask. | |
| threshold | FLOAT | 0.500–1 | Pixels with mask >= threshold become the edited image. |
| feather | FLOAT | 0.00–100 | Optional feather (in pixels) for a soft edge blend. 0 = pure hard mask (fully hash-perfect outside the mask). |
| maskopt | MASK | White = edited region, black = keep original. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |