Nodes/ComfyUI-MaskCanvasEditor/Mask Canvas Editor
ComfyUI Node

Mask Canvas Editor

The missing 'fit an image into a mask' node — drag it until it looks right

By ku1x·Created 2 months ago·Updated about a month ago· 0
Mask Canvas Editor
  • mask
  • image
  • cropped_image
  • cropped_mask
internal_imageNone

Positioning an image inside a mask in ComfyUI is normally blind guesswork: wire up ImageTransform and ImageCrop, punch in numbers, queue, squint at the result, punch in new numbers. Mask Canvas Editor is the "why are we doing this by hand" answer. You feed it a mask, it treats the mask's bounding box as a fixed window, and you drag, zoom, rotate, and flip the background image behind that window on a live floating canvas until it lands exactly where you want. Then you hit Apply and it crops for you.

It's a small node that solves a real, recurring annoyance - getting the right part of an image to show through a region defined by a mask. If you've ever wanted to fit a product photo into a detected frame, drop a face into a spotlight-shaped mask, or just crop a portrait so the subject isn't floating off-center, this is the tool. Nothing in core ComfyUI does it, and most mask utilities (WAS, Impact Pack) assume you already know the numbers.

How it works

The backend is genuinely simple, which is why it's so snappy. MaskCanvasEditor computes the bounding box of the mask (any pixel above a 0.5 threshold counts), then builds a reverse sampling grid: for every output pixel it works out where in the source image that pixel should come from after inverting your pan → rotate → scale → flip chain, and hands that grid to torch.nn.functional.grid_sample (bilinear, zero padding). One GPU call, no re-encoding, no faff.

Your transform state - scale, rotation, flips, x/y offset - travels as a JSON string on a hidden transform_state input, which is how it survives saving and re-loading your workflow. The frontend JS renders the same transform chain on an HTML5 canvas so the preview always matches the output. The author even makes it read the selected file from a connected LoadImage node in the browser, so you can compose before you've run anything once.

The inputs that matter

Only one is required: mask (MASK), which defines the crop window. The other two are optional and self-explanatory:

  • image (IMAGE) - the background you're positioning. Feed it a LoadImage and you can preview without queueing; runtime sources like SAM or RMBG outputs need one execution first.
  • internal_image - a file picker that reads from ComfyUI's input/ directory (that's why it lists filenames - check the input-folder docs if nothing shows up). Handy when you don't want a LoadImage node cluttering the graph.

Outputs are cropped_image (IMAGE) and cropped_mask (MASK) - the transformed image and the mask both cut to the mask's bounding box. Wire cropped_image into whatever composites it (or straight to PreviewImage to check your work).

Installation

Zero dependencies - the requirements.txt is literally a comment saying PyTorch comes bundled with ComfyUI. Either search Mask Canvas Editor in ComfyUI Manager, or:

cd ComfyUI/custom_nodes/
git clone https://github.com/ku1x/ComfyUI-MaskCanvasEditor.git

Restart ComfyUI. That's it. No models, no wheels, nothing to download.

Where people get burned

  • You must connect a mask or an image source. Neither connected and the node raises a clear ValueError - the UI isn't lying when it says "No image provided."
  • Runtime-generated masks need a first run. Masks from SAM, RMBG/BiRefNet, or anything that isn't a LoadImage show a placeholder window until you execute once, then the real bounding box kicks in. LoadImage's own alpha mask reads immediately.
  • The crop changes resolution per mask. Because output is cropped to the bounding box, a tiny mask gives a tiny image. That's usually what you want, but don't expect the output to match your original canvas dimensions.
  • An empty (all-black) mask quietly falls back to the full image as the window, so check your mask source before chasing a "wrong crop" bug.

For a niche utility with no dependencies, it's remarkably polished - and the kind of node you forget exists until you need it, at which point it saves you twenty minutes of queue-and-squint.

CategoryMask/CanvasEditor

Inputs (3)

NameTypeDefaultDescription
maskMASK
imageoptIMAGE
internal_imageoptCOMBONone2 options: None, example.png

Outputs (2)

NameTypeDescription
cropped_imageIMAGE
cropped_maskMASK