Nodes/resize_fill_background/Image Resize Fill Background
ComfyUI Node

Image Resize Fill Background

Don't stretch your inputs — pad them onto a solid canvas instead

By zhoul1·Created 5 months ago·Updated 5 months ago· 0
Image Resize Fill Background
  • image
  • image
  • WIDTH
  • HEIGHT
width512
height512
image_ratio1.00
fill_color#FFFFFF
methodnearest-exact

ComfyUI will happily stretch your source image to whatever width and height you feed it, and the results are usually ugly. If you're feeding a portrait-oriented photo into an img2img pass at 1024×1024, a straight resize squishes it into a diamond face and then the model "helpfully" keeps it. Image Resize Fill Background is the tiny fix: it scales your image to fit inside a target canvas without touching its aspect ratio, then centers it on a solid-color background. No distortion, no cropping, no black bars unless you want them.

It comes from the resize_fill_background pack, a single-node, zero-dependency utility. There's no model file, no API key, nothing to tune - the whole thing is one function that does contain-scaling and a centered paste.

Why you'd actually reach for it

Model training cares about resolution. SD 1.5 wants 512×512, SDXL wants 1024×1024-ish, and going far off-native ratio is where doubled arms and stretched torsos come from (see the resolution/aspect-ratio table in the KB's concepts essay). When you bring in an external image - a reference, a ControlNet source, a frame from a video - you often need it normalized to a specific canvas before it hits the model. The built-in resize nodes either distort or crop. This one pads, so nothing gets lost and nothing gets mangled.

It's also quietly good for the "hero product shot" look: an image floating on a clean colored background, like a listing photo. That's what the image_ratio input is for, and it's the distinctive thing about this node.

How it works

The mechanism is simple and it's right there in the source. Given your target width × height and an image_ratio, it computes the maximum area the image may occupy - width × ratio by height × ratio - then scales the source down to fit inside that box (contain, not cover). It creates a plain canvas of the full target size filled with fill_color, and pastes the scaled image dead center. With image_ratio at 1.0 that's a plain letterbox pad; at 0.75 the image only fills 75% of each axis, leaving an even margin on all sides. It loops over the batch, so video frames pass through fine.

The inputs that matter

Only two are worth thinking about, honestly:

  • image_ratio (0.1–1.0, default 1.0) - the margin knob. 1.0 = ordinary pad-to-canvas; 0.75 = image occupies 75% of each dimension, symmetric border around it.
  • method - and here's the trap: the default is nearest-exact. For pixel art that's perfect. For a photo, downscaling with nearest-neighbor looks crunchy and jagged. If you're not doing pixel art, switch it to lanczos (best quality) or bicubic. This is the #1 "why does my output look blocky" gotcha with this node.

width/height set the canvas (1–8192, defaults 512×512). fill_color is a hex string like #FFFFFF - the code even accepts 3-digit shorthand like #FFF. Outputs are the finished image plus WIDTH and HEIGHT INTs mirroring your canvas, handy for wiring into nodes that want explicit dimensions.

Installing it

The usual. ComfyUI Manager (search resize_fill_background), or manually:

cd ComfyUI/custom_nodes
git clone https://github.com/zhoul1/resize_fill_background

Restart ComfyUI. That's it - there's no requirements.txt and no model download. It only uses torch, Pillow, and numpy, which ComfyUI already ships.

Gotchas worth knowing

  • Transparency doesn't survive. The node works in RGB and pastes onto an opaque canvas, so any alpha channel gets flattened onto your fill color. Don't use it if you need to keep a transparent PNG.
  • A bad hex color raises an error, not a silent fallback - you'll get a ValueError mid-graph telling you the string isn't valid.
  • It contains, it never crops. If you expected a cover-style crop to fill the canvas edge-to-edge, this isn't that; pair it with a crop node if you want cover behavior.
  • It's a per-frame Python loop over the batch, so for hundreds of video frames it's not the fastest thing in the graph - fine for a preprocess step, just don't expect real-time.

For what it is - a 40-line node that does one boring job correctly - it's a solid little utility to have in the toolbox.

Categoryimage/transform

Inputs (6)

NameTypeDefaultDescription
imageIMAGE
widthINT5121–8192
heightINT5121–8192
image_ratioFLOAT1.000.1–1
fill_colorSTRING#FFFFFF
methodCOMBOnearest-exact4 options: nearest-exact, bilinear, bicubic, lanczos

Outputs (3)

NameTypeDescription
imageIMAGE
WIDTHINT
HEIGHTINT