ComfyUI Node

Jet Image Scale

Scale, Crop, or Letterbox in One Node — and Your Mask Comes Along

By JetterTW·Created 3 months ago·Updated 3 months ago· 1
Jet Image Scale
  • image
  • mask
  • image
  • mask
  • original_size
  • width
  • height
aspect_ratiooriginal
proportional_width1
proportional_height1
fitcrop
methodlanczos
scale_to_sidelongest
scale_to_length1280
background_color#000000

If you've ever built the resize-then-pad-then-math chain in vanilla ComfyUI just to get an image to a target aspect ratio, you know how fiddly it is. Jet Image Scale collapses all of that into one node: pick a ratio, pick how to fit it, and out comes a correctly sized image and a correctly aligned mask. No model downloads, no extra Python, just one file that does a job ComfyUI makes surprisingly annoying on its own.

Aspect ratio is where most of the classic failure modes live. Models are trained at specific ratios - SDXL's 1024x1024 and friends - and the standard trick from the KB is to generate at a nearby trained ratio, then crop or pad to your target (7:4 → crop to 16:9, for instance). That final crop/pad step is exactly what this node automates.

What it actually does

It takes an IMAGE (batch, height, width, channels) and optionally a MASK, and resizes to a target aspect ratio in one of three ways:

  • crop - scale so the image covers the target box, then center-crop the excess. This is the one you want for "generate at 7:4, output 16:9."
  • letterbox - scale so the image fits inside the box, then pad the leftover bars with a color you choose. Think YouTube's black bars, or padding a 1:1 generation up to 16:9 for a video workflow.
  • fill - just stretch/squeeze to the exact size. This distorts, and it's supposed to. Handy for compositing, rarely for final output.

Under the hood it converts each frame through PIL, does the resize with a real resampling filter (default lanczos, also bicubic, hamming, bilinear, nearest), and converts back to a tensor. It handles grayscale, RGB, and RGBA inputs. The mask gets resized, cropped, or padded with the exact same geometry, so it stays pixel-aligned with the image - that's the feature that stops you hand-rolling a broken version.

The inputs that matter

You'll touch maybe five of these:

  • aspect_ratio - presets for 1:1, 3:2, 4:3, 16:9 and their rotations, plus original (no ratio change, just resize) and custom. Portrait is 9:16, not 16:9; the ratio is always width:height.
  • proportional_width / proportional_height - the two ints that define custom. Want 21:9? 21 and 9.
  • fit - crop, letterbox, or fill, above.
  • scale_to_side + scale_to_length - this sets the size, not just the shape. longest/shortest anchor on the longest/shortest edge to scale_to_length (default 1280), or you can pin width/height directly. none is the subtle one: it keeps the image's original pixel scale and only adjusts the canvas to the target ratio.
  • background_color - hex for the letterbox bars. Defaults to #000000, so if you're padding a white-background workflow, set it.

The optional mask in: resized with the image, so it's safe to feed into inpainting or ControlNet conditioning downstream. Even without a mask it still emits one (all zeros) at the new size, so the output wires cleanly.

Outputs

image and mask are the obvious ones. original_size (a TUPLE of the pre-resize width, height) is handy if you later want to go back to source dimensions. And width / height as plain ints let you feed exact numbers into an empty-latent node or a text prompt that wants the real size.

Installing it

The boring, reliable way:

cd ComfyUI/custom_nodes
git clone https://github.com/JetterTW/ComfyUI-JetImageScale.git

Then restart ComfyUI. ComfyUI Manager finds it as ComfyUI-JetImageScale if you'd rather click. There's no requirements.txt and no models to fetch - the whole node is one Python file using only torch, numpy, and PIL, all of which ComfyUI already ships. It's about as low-risk a custom node as exists in an ecosystem where that's worth checking.

Where people get tripped up

The biggest misunderstanding: this resizes, it doesn't upscale. Lanczos interpolation is a great "more pixels, source already sharp" tool - the KB still recommends it there - but it can't invent detail. If you're upscaling for quality, run this for the layout and a real upscaler (SeedVR2 or an ESRGAN variant) for the pixels.

Also remember it's a single node, not a full workflow: if your letterboxed image is going into a model, match the latent size too, or the bars you added get resampled again. And check background_color before you wonder why your padding is black.

It won't change your life, but the next time a workflow demands a specific ratio, you won't be digging out a resize node, a pad node, and a calculator. That's a win.

CategoryImage/Scale

Inputs (10)

NameTypeDefaultDescription
imageIMAGE
aspect_ratioCOMBOoriginal9 options: original, custom, 1:1, 3:2, 4:3, 16:9, +3
proportional_widthINT11–99999
proportional_heightINT11–99999
fitCOMBOcrop3 options: crop, letterbox, fill
methodCOMBOlanczos5 options: lanczos, bicubic, hamming, bilinear, nearest
scale_to_sideCOMBOlongest5 options: none, longest, shortest, width, height
scale_to_lengthINT12801–99999
background_colorSTRING#000000
maskoptMASK

Outputs (5)

NameTypeDescription
imageIMAGE
maskMASK
original_sizeTUPLE
widthINT
heightINT