KoO.Load Image & Crop
Load an Image and Crop It in One Node, With the Numbers to Prove It
- image
- mask
- crop_x
- crop_y
- crop_width
- crop_height
- crop_label
- original_width
- original_height
- cropped_width
- cropped_height
The standard img2img opening is two nodes: Load Image, then a crop or pad node, then a resize, and by the third one you've lost track of what resolution anything is. KoO.Load Image & Crop collapses that into one node with a drag-to-crop UI on its face, and - more usefully - it exposes every dimension it decided on as an output.
That last part is what separates it from a dozen lookalikes. The crop isn't just applied; it's reported. crop_x, crop_y, crop_width, crop_height, original_width, original_height, cropped_width, cropped_height and a crop_label string all come out as sockets, so downstream nodes can plan against real numbers instead of hoping.
How it works
You pick a file from ComfyUI's input folder in the image dropdown. Everything else is geometry:
crop_x,crop_y,crop_width,crop_height- the rectangle. These are driven by the on-canvas crop UI; you can type them, but the UI is the point.crop_enabled- whether a crop is in play at all.crop_confirmed- a second flag, set when you commit the rectangle in the UI.optimize_long_side-Off, or 512 / 768 / 1024 / 1344 / 1536 / 1920 / 2048. Rescales the result so its long edge hits that value, preserving aspect.
Both crop flags have to be true for the crop to apply. If either is off, the node passes the full frame through and the geometry outputs describe a full-frame crop. That's a deliberate two-step - you can drag a rectangle, look at it, and decide not to commit - but it's also the number one source of "my crop isn't doing anything."
Two dependency notes from the source. If comfy_api.latest's InputImpl is available the node can load video files and take the alpha channel as a mask; if that import fails it logs a note and falls back to Pillow. And the mask output is derived from the alpha channel - 1.0 − alpha/255, so transparent becomes 1 - meaning a JPEG with no alpha gives you an all-zero mask. Useful for PNG mattes, useless for anything opaque.
It also gets caching right: IS_CHANGED hashes the file's bytes plus all six geometry widgets, so editing the source file on disk or nudging the crop each invalidates properly. Very few loader nodes bother.
The outputs, and what to wire where
image (IMAGE) is the crop, ready for a VAE Encode. mask (MASK) is the alpha cutout, or zeros. crop_label is a human-readable crop x=128 y=64 w=896 h=1152 string - genuinely handy for filename templates and log nodes.
The eight integers are for planning: feed cropped_width/cropped_height into a resolution node so your generation matches the crop's aspect, or branch on original_width versus original_height to handle portrait and landscape sources differently. This is the plumbing argument in miniature - one node owning a value and fanning it out beats four widgets typed by hand and kept in sync by memory.
Installing it
cd ComfyUI/custom_nodes
git clone https://github.com/kevintronchin-blip/koo-nodes-pack
Restart and refresh the browser. The crop UI is a frontend component, so a stale cache will show you a bare node with no rectangle. Dependencies are the four ComfyUI already provides (torch, numpy, Pillow, aiohttp); no models, no downloads. Category is KoO Tools / Image.
Like the rest of the pack's custom canvases, this one needs the Legacy / LiteGraph renderer - under Nodes 2.0 the node-level drawing and mouse hooks don't run. Registry/Manager listing at v1.0.3 is pending moderation approval, so source-ZIP installation (extracted to ComfyUI/custom_nodes/koo-nodes-pack, __init__.py directly inside) is the reliable route.
Troubleshooting
Crop does nothing. Check both crop_enabled and crop_confirmed. Dragging a rectangle in the UI sets the numbers; confirming commits them.
The mask is all black. Your source has no alpha channel. This node doesn't guess a subject mask - it reads transparency. If you want a semantic mask, that's a different tool.
Output resolution isn't what you cropped. optimize_long_side is set. It rescales to the long-edge value you picked, which changes cropped_width/cropped_height but not crop_width/crop_height - the two pairs deliberately describe different stages.
File not found after moving images around. The dropdown stores a filename relative to ComfyUI's input folder and validates it on queue; move or rename the file and you'll get a clean "Invalid image file" error rather than a traceback.
One last thing worth knowing: this pack also ships KoO.Load Image & Crop Next, a newer sibling that outputs a single KOO_CROP_DATA bundle instead of loose integers, designed to pair with KoO Crop Data Unpack. If you're starting fresh and want the tidier wiring, that's the one; this node is the simpler, more explicit option.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| image | COMBO | 1 options: example.png | |
| optimize_long_side | COMBO | Off | 8 options: Off, 512, 768, 1024, 1344, 1536, +2 |
| crop_x | INT | 00–16384 | — |
| crop_y | INT | 00–16384 | — |
| crop_width | INT | 00–16384 | — |
| crop_height | INT | 00–16384 | — |
| crop_enabled | BOOLEAN | false | — |
| crop_confirmed | BOOLEAN | false | — |
Outputs (11)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| mask | MASK | — |
| crop_x | INT | — |
| crop_y | INT | — |
| crop_width | INT | — |
| crop_height | INT | — |
| crop_label | STRING | — |
| original_width | INT | — |
| original_height | INT | — |
| cropped_width | INT | — |
| cropped_height | INT | — |