Fit Image into BBox Mask
Put an image exactly where the mask says — pose compositing without the guesswork
- source
- mask
- destination
- composite
- fitted_source
- placed_mask
- x
- y
- w
- h
Let's say you've got a pose image, a logo, a decal, or a product shot you need to drop into a scene - and it has to land in a specific region, scaled to fit, without you eyeballing the resize. This node is that whole job in one box: it reads a mask, finds the smallest rectangle that covers its white pixels, resizes your source image to fit inside that box while keeping the aspect ratio, and pastes it onto a destination image (or a fresh canvas). Out comes the composited result, plus the fitted image and mask on their own, so you can feed them anywhere.
The author's stated intent is inpainting: fit the image into the masked area, pre-process it, then run a ControlNet on that region. It's the "exact placement" half of the old masked-inpainting recipe - and even in 2026, when whole-frame edit models do most of the work, exact placement is still the one thing masks own outright.
How it works
The mechanism is refreshingly simple, all PIL math:
- The mask is thresholded - any pixel at or above
threshold(default 0.5) counts as "set" - and the bounding box is computed from those pixels. - That box is expanded outward by
padpixels, clamped to the canvas. - The source is resized to fit inside the box (
fit, no crop) or cover it (fill, cropping edges as needed). - Alignment and pixel
offset_x/offset_yplace it, and it's pasted onto the destination. - The
placed_maskoutput is the intersection of the mask and the footprint rectangle - i.e. "exactly where the image actually landed."
The mask is resampled with nearest-neighbor to the destination's size if they don't match, so a small mask still works on a big canvas.
Inputs and outputs that matter
Two required inputs drive everything: source (the image you're inserting) and mask (its white area defines the box). The rest are polish:
- mode -
fitscales inside the box with no crop (default);fillcovers it completely and crops the overflow. - align_x / align_y - where the fitted image sits in the box when the aspect ratios don't match. Center is the sane default; the edge options matter when a mask box is much wider than your decal.
- threshold - mask brightness cutoff for box detection. 0.5 works for crisp masks; drop it for soft or faint ones.
- pad - grows the box outward by N pixels, handy for giving your insert breathing room.
- use_source_alpha - if on, transparent areas of the source are respected during the paste. Leave it off for fully opaque images.
- destination (optional) - what you're compositing onto. Omit it and you get a blank
canvas_w×canvas_hcanvas (default 1024×1024). - antialias - lanczos (default), bicubic, or bilinear resampling.
Outputs: composite (destination + fitted source), fitted_source (the resized image on a black canvas - wire this into a ControlNet preprocessor or an inpaint pass), placed_mask (the exact placed region), and x, y, w, h (the box coordinates/dimensions, if you want them for other math). It's batch-aware: feed N sources and it returns N composites.
Installing
No dependencies, no model files - the pack is pure Python on top of ComfyUI's existing PIL/torch.
- ComfyUI Manager: search "ComfyUI vsLinx Nodes", install, restart.
- Manual:
cd ComfyUI/custom_nodes
git clone https://github.com/vslinx/ComfyUI-vslinx-nodes.git comfyui-vslinx-nodes
Restart, and it's under vsLinx/inpaint.
Gotchas
- An empty or black mask is a silent no-op. If no pixel crosses the threshold, the bounding box doesn't exist, and the node passes your destination through unchanged with a black fitted image and an empty mask. No error - you just get "nothing happened." If that's what you're seeing, your mask has no white in it, or your threshold is too high for a faint mask.
fillcrops. Great when you need to cover the box edge-to-edge, but parts of your source will be cut. If the source's edges matter (a logo, a face), stay onfit.- Sections of the mask with feathered edges can shrink or shift the detected box. The threshold applies per-pixel, so a heavily feathered mask measures differently than the shape you think you painted. Raise
padto compensate.
It's a small node, but it's the difference between compositing by hand with three separate nodes and doing it in one. For decal, pose, and product-shot workflows, it earns its place.
Inputs (14)
| Name | Type | Default | Description |
|---|---|---|---|
| source | IMAGE | The image you want to insert (e.g. pose, object, decal). | |
| mask | MASK | Defines where the image will be placed. The white area determines the bounding box. | |
| mode | COMBO | fit | fit scales the image inside the mask’s box (no crop). fill covers the box completely (may crop edges). |
| align_x | COMBO | center | Alignment on the x axis of the fitted image inside the box if the aspect ratio doesn’t match perfectly. |
| align_y | COMBO | center | Alignment on the y axis of the fitted image inside the box if the aspect ratio doesn’t match perfectly. |
| offset_x | INT | 0-4096–4096 | Manual pixel offset on the x axis for fine-tuning the placement. |
| offset_y | INT | 0-4096–4096 | Manual pixel offset on the y axis for fine-tuning the placement. |
| threshold | FLOAT | 0.500–1 | Mask brightness threshold for detecting the box. 0.5 works for most cases. |
| pad | INT | 00–4096 | Expands the bounding box outward by N pixels. |
| use_source_alpha | BOOLEAN | false | If true, respects transparency in the source image during paste. |
| antialias | COMBO | lanczos | Resampling method used when resizing the source image. |
| destinationopt | IMAGE | The image you’re compositing onto. If not provided, a blank canvas is created. | |
| canvas_wopt | INT | 102416–8192 | Canvas width when no destination image is given. |
| canvas_hopt | INT | 102416–8192 | Canvas height when no destination image is given. |
Outputs (7)
| Name | Type | Description |
|---|---|---|
| composite | IMAGE | — |
| fitted_source | IMAGE | — |
| placed_mask | MASK | — |
| x | INT | — |
| y | INT | — |
| w | INT | — |
| h | INT | — |