Poly Mask Loader (Multi)
Poly Mask Loader (Multi)
- IMAGE
- MASK
You know the drill. You need a mask for an inpaint or a local edit, and suddenly you're fighting ComfyUI's canvas or painting blobs in an external editor and exporting them back in. Poly Mask Loader (Multi) skips all of that: it's a mask editor that lives inside the node. Pick an image, click a polygon out on the little canvas that appears in the node, and it hands you an IMAGE plus a ready MASK. No export, no PIL scripts, no leaving the graph.
It's the flagship of ComfyUI-PolyMask, a tiny MIT pack from Carasibana. The "Multi" is the one you actually want: up to six polygons, additive and subtractive modes, and a base-layer switch. The plain sibling in the same pack just does one polygon.
How it works
The Python half is simple - an image loader plus a polygon rasterizer. The magic is the canvas, which is a JavaScript frontend extension shipped in the pack's js/ folder. It draws an interactive editor over the image directly on the node: left-click adds a point, drag moves one, clicking on a line inserts a point, right-click deletes. Every edit updates a JSON string widget (polygon_data), and because IS_CHANGED includes that data, ComfyUI re-runs downstream as you drag. You watch the mask update live.
On each run the node loads the image (EXIF orientation handled, RGBA composited onto white), parses polygon_data, and draws each polygon with PIL's ImageDraw. Additive polygons union into the mask (np.maximum); subtractive ones carve out anything they cover. Polygons process in order 1→6, so higher numbers win in overlaps - the subtractive shapes show up dashed and dark on the canvas so you can tell them apart.
The base layer sets the starting state: false means the mask starts empty, true starts fully opaque. The README documents a neat auto-switch: add your first point to a subtractive polygon while the base is empty and nothing else exists, and it flips to Full for you - subtraction needs something to subtract from.
The inputs that matter
image- a dropdown of everything in your ComfyUI input folder, with an upload button.feathering(0–100) - blurs the mask edges. 0 is hard-edged; a few pixels hides seams (4–12px is the usual range for inpaint masks).polygon_data- the JSON string the canvas writes for you. You don't type this.base_layer(boolean) -false= empty base,true= full base.
Outputs are IMAGE and MASK. Wire the MASK into Set Latent Noise Mask for classic masked inpainting, or InpaintModelConditioning for Flux/Qwen-style edits; the IMAGE output means it doubles as a LoadImage, keeping mask and source in sync in one node.
Install
ComfyUI Manager → search "PolyMask", or:
cd ComfyUI/custom_nodes
git clone https://github.com/Carasibana/ComfyUI-PolyMask.git
Then restart ComfyUI. No model downloads, no heavy dependencies - requirements.txt is just torch, numpy, and Pillow, all of which ComfyUI already has. There's zero VRAM weight to this thing; it's pure UI plus a rasterizer.
Where people get burned
- The canvas is a frontend extension, so if you don't see it after install, restart ComfyUI and hard-refresh the browser tab.
- A polygon with fewer than 3 points is silently skipped - a two-point "shape" quietly does nothing. Not obvious, since the canvas lets you leave it that way.
- Feathering isn't a pure softener: the code takes the max of the original mask and the blurred one, so the blur adds a halo that grows the mask outward. Crank it high and you're not just softening, you're expanding coverage.
- The mask is stored as JSON inside the workflow, which is a feature - it travels with the workflow when you share the PNG.
For a single simple region this node is honestly overkill - the plain Poly Mask Loader is lighter. But the moment you want a cutout with a hole in it, or a shape assembled from a couple of polygons, the Multi is the one that's actually there.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| image | COMBO | 1 options: example.png | |
| feathering | INT | 00–100 | — |
| polygon_data | STRING | [] | — |
| base_layer | BOOLEAN | false | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |
| MASK | MASK | — |