Nodes/ComfyUI-off-suite/VAE Encode For Inpaint V2
ComfyUI Node

VAE Encode For Inpaint V2

The Proper Way to Feed a Mask Into an Inpaint Sampler

By Off-Live·Created 3 years ago·Updated 2 years ago· 0
VAE Encode For Inpaint V2
  • pixels
  • vae
  • mask
  • LATENT
  • IMAGE
  • MASK
mask_blur6

Mask-based inpainting in ComfyUI isn't just "draw a mask and sample" - the masked region needs to be encoded so the sampler knows what's fixed and what's free, and the way you encode it decides whether your inpaint has clean seams or a visible rectangle. This node is that encode step, done the way the Impact Pack does it: it blanks out the masked region before encoding and hands the sampler a noise_mask that's been shrunk so the generated content stays inside the mask instead of bleeding across the boundary.

It's part of ComfyUI-off-suite, and it's a re-implementation of the well-known VAE Encode For Inpaint approach with a boundary trick on top. If you've been doing face inpaints with a bare KSampler and wondering why the seams look wrong, this is likely the missing piece.

What you plug in

  • pixels - the IMAGE to encode.
  • vae - the VAE to use (must match your checkpoint family).
  • mask - the inpaint region.
  • mask_blur - default 6, range 0–64. Blurs the mask edge so the transition between original and generated pixels is a gradient instead of a hard line. The classic seam-killer.

What comes out

Three outputs, and the first one is the workhorse:

  • LATENT - the encoded image with a noise_mask attached. This is what you wire into the KSampler. The noise_mask is what tells the sampler "only denoise inside here." It's automatically derived from your mask, and the erosion trick means the sampler gets a slightly smaller region than your drawn mask - the comment in the source spells out why: it shrinks the mask area so the boundary has better continuity.
  • IMAGE - the (possibly trimmed) pixels that were actually encoded, for preview.
  • MASK - the blurred version of your mask, so you can see what the sampler will actually respect.

The mechanism that makes it "V2"

Two encode-time details separate this from a naive approach. First, the masked region is zeroed in the pixel space (multiplied by 1 − mask) before the VAE encode - the "mask content" question answered with "nothing," so the latent genuinely starts empty where you want regeneration. Second, the erosion: the actual noise_mask is a shrunk version of your drawn mask, which is the difference between a face fix that blends into the skin and one that visibly crops the cheek. For face work this matters a lot; it's the same insight ADetailer-style detailers rely on.

Gotchas

  • The mask_blur path uses OpenCV's GaussianBlur under the hood, so it needs the mask as a plain tensor - fine for anything ComfyUI produces.
  • Pixels are trimmed to multiples of 8 before encode (with the offset centered), so your output IMAGE may be a few pixels smaller than the input. Keep that in mind if you're pasting the result back onto the original - pair it with the pack's Paste Face Segment to Image and use the crop's own CROP_DATA rather than assuming exact alignment.
  • It's a VAE encode, not a sampler - you still need a KSampler after it, set to use the latent's noise_mask, with a sensible denoise (0.5–0.8 for most face fixes; the KB's inpainting guidance on denoise settings applies here too).

Install

cd ComfyUI/custom_nodes
git clone https://github.com/Off-Live/ComfyUI-off-suite
# or: ComfyUI Manager → search "ComfyUI-off-suite"

No extra Python deps (OpenCV is bundled with ComfyUI). The core ComfyUI node VAE Encode For Inpaint covers the basic case; this V2 is worth it when boundary quality matters, which for faces it almost always does. Repo's been quiet since mid-2024 - frozen, but this kind of encode logic doesn't rot.

CategoryOFF

Inputs (4)

NameTypeDefaultDescription
pixelsIMAGE
vaeVAE
maskMASK
mask_blurINT60–64

Outputs (3)

NameTypeDescription
LATENTLATENT
IMAGEIMAGE
MASKMASK