♾️ Image Crop
Drag a box on the image to pick the crop — and its mask comes along
- image
- mask
- source
- cut
- size
- x
- y
- cut_mask
The most annoying thing about crop-and-stitch inpainting in ComfyUI is picking the crop. You type x, y, and size into three widgets, run, look, and type them again because the region was off by twenty pixels. Image Crop (ImageCropLoop) removes the typing: it shows you the image right in the node, you drag the rectangle where you want it, and x/y/size update themselves. It's the first half of the ComfyUI-Loop pack's crop-and-paste pair, and its superpower is that it crops the image and your mask together, so the inpainting mask stays aligned with the cut by construction.
How it works
The crop itself is boring - it slices image[:, y:y+size, x:x+size, :] and clamps everything so the crop stays inside the image bounds. The interesting part is the preview. The node downscales the image (to a 1024px preview internally), writes it to ComfyUI's temp folder, and pushes it to the frontend over a websocket event; the bundled JS renders the crop rectangle on top. Drag the rectangle or the marker and x/y/size update live; hover over the preview and hit PageUp/PageDown to grow or shrink the crop. A binary preview of the mask draws over the same image when show_mask is on.
One nice touch: preview files are cached by an image hash, so if the inputs haven't changed, a re-run doesn't regenerate the preview. It keeps iteration snappy and is the sort of detail that tells you the author actually uses this thing.
The inputs that matter
image- what you're cropping.x/y- crop origin, 0–32768. Set them by dragging; the widgets just reflect it.size- crop size, default 512, range 256–2048, in increments of 8 (the tooltip says it and the JS enforces it - the dial snaps to 8px steps).color- rectangle color for the preview: black, grey, red, green, blue. Cosmetic, but red on a dark image is a lifesaver.show_mask- toggle the binary mask preview on/off.mask(optional) - a mask cropped along with the image.
Outputs: source (the original, untouched - pass-through), cut (the cropped square), size / x / y (the actually used values, after clamping), and cut_mask (the cropped mask region). The full bundle wires directly into ♾️ Paste Image: cut→cut, x→x, y→y, cut_mask→cut_mask.
Why the clamped outputs matter
This is the subtle part beginners trip on. If you type size: 2048 into a 1024px image, the node clamps to 1024 - and the size, x, y outputs reflect reality, not what you typed. Feed those outputs forward instead of re-typing, and your Paste Image step always matches the actual cut. It's the "spend the generation budget only inside the region" philosophy from the inpainting playbook, made structural: the crop node tells you exactly what it did.
Install and gotchas
Same as the rest of the pack - no dependencies, no model downloads:
cd ComfyUI/custom_nodes
git clone https://github.com/Hullabalo/ComfyUI-Loop
Restart, and the ♾️ Image Crop node appears under LOOP. ComfyUI Manager users: search "Loop."
- It's the most frontend-fragile node in the pack. The interactive overlay depends on the legacy canvas and custom JS, and the pack is explicitly not compatible with Nodes 2.0 - the author says it will almost certainly never be. If you're on the new Vue frontend, drag-to-crop simply won't work.
- No batch support. One image at a time, no lists.
- The mask is optional, but resize it with the image. If you feed a mask at a different resolution, the node resizes it to match the image first, so it stays aligned - but only if you actually pass one in.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| x | INT | 00–32768 | x origin of the crop. |
| y | INT | 00–32768 | y origin of the crop. |
| size | INT | 512256–2048 | size of the crop. By 8 pixels increments. |
| color | COMBO | black | Color of the crop rectangle in the preview. |
| show_mask | BOOLEAN | true | Show or hide preview mask |
| maskopt | MASK | — |
Outputs (6)
| Name | Type | Description |
|---|---|---|
| source | IMAGE | — |
| cut | IMAGE | — |
| size | INT | — |
| x | INT | — |
| y | INT | — |
| cut_mask | MASK | — |