Crop by Margins (Image)
Pixel-perfect margin crops with a snap-to-multiple knob
- image
- IMAGE
Every image workflow eventually needs the dumbest possible operation done correctly: crop off N pixels from each edge. ComfyUI's built-in tools can do it, but they're usually tied to aspect ratios or bounding boxes, and the arithmetic to shave a border off a real photograph is annoying to keep in your head across a whole batch. CropImageByMargins is that operation, done once, with one genuinely useful twist.
The inputs are exactly what they look like: image plus left_px, top_px, right_px, and bottom_px (each 0–16384). Put in how many pixels to strip from each side, get the cropped IMAGE out. You can even go asymmetric - trim 40px off the bottom of a scan that has a wider border there and nothing off the top.
The knob worth understanding is snap_multiple. After cropping, the node rounds the resulting dimensions down to a multiple of this value (default 1, meaning no snapping). Set it to 8 or 16 and the output dimensions stay friendly to tile-based processing; set it to 64 and your crops land on clean bucket boundaries. It's a small thing that saves you from "why is this 1342 wide instead of 1344" downstream. There's no resize happening here - just a crop and an optional rounding of the leftover dimension - so the output is always a strict sub-region of the input, same pixels.
This is the sibling of CropMaskByMargins (same inputs, but takes and returns a MASK), and the pair is designed to be used together: crop the image and its mask with identical margins so your subject region stays aligned with the pixels that represent it.
Install
Standard PortraitUtils - Manager → search "PortraitUtils", or:
cd ComfyUI/custom_nodes
git clone https://github.com/heyburns/PortraitUtils
Restart after cloning. Pure tensor slicing on torch/numpy; no extra deps.
Common issues
- Nothing visibly changes - check the margins actually are nonzero, and remember 0–16384 is the range, so a "5" is 5 pixels and easily missed at a glance.
- Cropped edge is slightly ragged - that's
snap_multipledoing its rounding. If you want the exact margins, leave it at 1. - Image and mask go out of sync - you edited margins on one and not the other. Keep them wired to the same values (or the same config node) and they'll track each other.
It's the unglamorous workhorse of the pack: no AI, no cleverness, just correct, batchable, dimension-safe cropping. Sometimes that's exactly what a workflow needs.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| left_px | INT | 00–16384 | — |
| top_px | INT | 00–16384 | — |
| right_px | INT | 00–16384 | — |
| bottom_px | INT | 00–16384 | — |
| snap_multiple | INT | 11–512 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |