Change Image Border
It paints a border on your image — it doesn't add one
- image
- image
The name tells a small lie you only notice after the run: Change Image Border doesn't pad your image with a strip of color. It recolors the outer border_size pixels that are already there, and hands you back an image the exact same size. Dimensions in = dimensions out, just with a frame painted over the edge. It's a cosmetic utility, and honestly that's all it's trying to be. That's not a criticism - sometimes you just want a thin black frame on a batch of outputs, and a dedicated node beats firing up an editor.
What it's for
Reach for it when you want a uniform edge on finished images:
- Framing batch generations so a grid or contact sheet doesn't blur into itself
- Giving preview thumbnails a consistent dark edge before you drop them into a gallery, a video, or a composite
- Quick "vignette-ish" darkening of an image's edge without leaving ComfyUI
But if what you actually want is to grow the image with padding - room for outpainting, or a caption strip along the bottom - this is the wrong node. Core ComfyUI's Pad Image nodes do that by resizing the canvas. ChangeImageBorder is a picture frame, not a mat, and confusing the two is the easiest way to end up confused.
How it works
The whole pack is one ~100-line file, and the mechanism is plain pixel poking. Each input image becomes a PIL image, gets converted to RGBA, and numpy slices the top, bottom, left, and right strips of border_size pixels. Those strips get overwritten with [value, value, value, 255] - your color at full alpha - and the result is converted back to a tensor. Batches work: feed it ten images and it loops through each and concatenates them back together. No models, no weights, no downloads, no dependencies beyond numpy/PIL/torch that ComfyUI already ships. This is as close to dependency-free as a custom node gets, which in the ecosystem's usual dependency hell is genuinely refreshing.
The inputs that matter
- image - any IMAGE tensor you have around.
- value (INT, default
0) - the border color. Here's the catch: it's a single grayscale value from 0–255, applied identically to the red, green, and blue channels.0is black,255is white, everything between is some gray. There is no hue input, so you cannot make a red or blue border with this node. If you need a colored frame, you'll be using ImageCompositeMasked or a color node instead. - border_size (INT, default
2) - the thickness of the frame in pixels. A2reads as a thin outline; crank it to10+ on a big image and it starts to look like a real frame.
Output is image, same IMAGE type. The one subtle gotcha: the node converts internally to RGBA, so your 3-channel RGB input comes back as 4-channel RGBA with a solid alpha. Most downstream nodes shrug at that, but a few expect exactly three channels and will throw an odd error - worth knowing before you wonder why your pipeline suddenly grew a channel.
Install
The standard two ways:
- ComfyUI Manager → Install Custom Nodes → search for Change Image Border (pack name
ComfyUI_Change_IMAGE_BOREDER) → install and restart. - Manual:
Then restart ComfyUI. Nocd ComfyUI/custom_nodes git clone https://github.com/githubYiheng/ComfyUI_Change_IMAGE_BOREDERrequirements.txt, no model files - the pack is a single Python file, so there's nothing to go wrong on install.
Gotchas & troubleshooting
- It prints
aaaaaandbbbbto your console every run. Harmless debug leftovers from the author. Cute, slightly embarrassing, and a good reminder this is a quick utility rather than a polished library. (The pack's README has since been deleted - git history says "fix: remove readme" - so the code is the only documentation, and it's accurate.) - Border color is gray-only. If you expected a full color picker, the single
valueINT is all you get. - Overwrite, not pad. If your image didn't grow, that's correct behavior. If you wanted it to grow, you need an image-pad node.
- Node missing after install? Restart ComfyUI, and confirm the folder landed in
custom_nodes/with the__init__.pyintact.
It's a small tool with one honest job. If that job matches your workflow - a clean frame on a batch of outputs - it'll do it without fuss and without dragging in a single extra dependency.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| value | INT | 0 | — |
| border_size | INT | 2 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |