✂️ 遮罩裁切并放大 Magic Mask Crop & Resize
Give the 64-pixel eye its own 1024px canvas
- image
- mask
- cropped_image
- cropped_mask
- crop_info
- mask_empty
The problem this actually solves
A face that takes up 70 pixels of a 1024px frame comes out as a smear, and it doesn't matter how good your checkpoint is - the latent has no budget to spend on that region. The old fix was "only masked" inpainting: crop the region, upscale it to the model's native resolution, let it render there, paste it back.
That pattern is now how people run modern edit models too. Qwen-Image-Edit and Flux 2 Klein are great at describing what should change and terrible at leaving the rest of the frame alone - everything outside your mask returns subtly different, and it compounds across edits. Hence the 2026 answer: keep the mask, run the edit model inside it, and never let the unmasked pixels touch a VAE.
Magic Mask Crop & Resize is the first half of that. Give it an image and a mask; it hands you a square crop with padding around the active mask region, resized to whatever your model wants, plus a CROP_INFO object the merge node uses to put the result back where it came from. If you know lquesada's Inpaint Crop and Stitch, this is that idea re-implemented inside an all-in-one utility pack. The pair landed in pack v1.4.3 on 2026-09-29, so there's no pile of forum threads to lean on - everything below is read from the shipped source.
How the crop gets computed
The mask is thresholded (mask > mask_threshold, default 0.001 - any nonzero pixel counts as active). If nothing is active, the node bails out of cropping and just resizes the whole image to your target size, returning a blank mask and mask_empty = True. That's the fallback, not a bug, and it's what makes the pair safe to leave in a workflow that sometimes has no mask.
Otherwise it takes the bounding box of the active region, works out side = max(width, height) + 2 * padding, centres that square on the box's centre, and cuts. Square because edit and inpaint models are happiest at fixed dimensions; padded because a tight bounding box gives the model no context to blend against.
One detail before you batch: the box is computed once per batch, from the union of every active mask in it. Not per frame. Ten images with masks in ten different corners gets you one enormous crop covering all of them.
When the square runs off the edge of the image the node zero-pads it so the crop stays complete. That filler sits outside the original bounds, so the merge node never pastes it back - a mask near the frame edge gets you neither truncated corners nor black bars.
The inputs you actually set
target_width/target_height- the resolution your edit model wants. 1024×1024 is the usual answer; match the model, don't guess.padding- default 64px, added to the longer side of the mask box before squaring. For a hand or an eye going into a strong edit model, 96–128 gives it more to match against. Too little and you get a visible seam, too much and you're rendering pixels you didn't need.mask_threshold- leave it at 0.001 unless your mask is soft and the feather ring is inflating the box; then try 0.05–0.1.upscale_method-lanczos, the right default. The mask itself is always resized bilinearly internally, which is deliberate; lanczos on a mask rings.mask- optional, and it's the whole point. Without a mask you're just resizing the image.
Outputs and where they go
Four. cropped_image and cropped_mask feed your inpainting or edit-model chain - keep a separate wire from the original image for later. crop_info goes into MagicMaskResizeMerge and nowhere else; nothing else understands the type. mask_empty is a boolean for the no-mask case.
Install
One clone gets you the whole 12-node pack. In ComfyUI Manager, search ComfyUI-Magic-Assistant. Manually:
cd ComfyUI/custom_nodes
git clone https://github.com/shigjfg/ComfyUI-Magic-Assistant.git
cd ComfyUI-Magic-Assistant
pip install -r requirements.txt
Then restart. requirements.txt is just openai and aiohttp, neither of which this node uses at runtime - no model downloads, no compiled wheels. The SDNQ extras in requirements-sdnq.txt are for the SDNQ nodes only. On startup the console prints a 🔮 [Magic Assistant] 已加载 banner listing every registered node; that's your proof the pack loaded.
Where people get burned
You searched for "Magic Mask" and found nothing. The display name is bilingual: ✂️ 遮罩裁切并放大 Magic Mask Crop & Resize. Search Mask.
Nothing from the pack appears in the node list. This is the pack-specific trap: __init__.py imports every node module at startup, so one broken sibling (the Nunchaku Klein loader and Photopea are the fiddly ones) can take the whole pack down, including these two. If the console banner is missing, read the traceback rather than reinstalling, and update all the files at once; the README says so explicitly for the post-0.29.0 changes.
Everything comes back blurry-smeared instead of sharp. Check mask_empty. If it's True, the mask never reached the node and you're feeding a whole image to a model expecting a detail patch.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| target_width | INT | 10241–16384 | — |
| target_height | INT | 10241–16384 | — |
| padding | INT | 640–4096 | — |
| mask_threshold | FLOAT | 0.0010–1 | — |
| upscale_method | COMBO | lanczos | 6 options: nearest-exact, bilinear, area, bicubic, lanczos, bislerp |
| maskopt | MASK | — |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| cropped_image | IMAGE | — |
| cropped_mask | MASK | — |
| crop_info | CROP_INFO | — |
| mask_empty | BOOLEAN | — |