Video Resize (TJ)
Five Resize Modes in One Node, and It Rounds to Even Pixels
- images
- images
- width
- height
Every video workflow has the same awkward middle. You've loaded or generated frames, they're the wrong size for what comes next, and now you're chaining ImageScale into ImageScaleBy into a crop node and hoping the maths works out. Video Resize (TJ) folds the whole thing into one node with a mode switch - and it uses comfy.utils.common_upscale internally, the exact function core's ImageScale and ImageScaleBy call, so the scaling quality and crop maths are the same ones you already trust rather than someone's reimplementation.
It sits between a frame loader (VHS_LoadVideo, a video VAE decode) and whatever encodes the result (CreateVideo, VHS_VideoCombine). In that position it's doing one of two jobs: fitting frames to what a model or encoder will accept, or reframing them.
The five modes
Long side and Short side both keep aspect ratio and hit target_px on one edge - the other edge follows. Long side is the usual "make this 1080p-ish" move; short side is what you want when a model cares about the smaller dimension.
Ratio is the odd one and the one people misread. It does not scale. It centre-crops to ratio_w:ratio_h at the source's own resolution. So 16:9 out of a 4:3 clip gives you a narrower frame at the same pixel height, not a resized one. If you were expecting a resize, that's a surprise; if you were expecting a crop, it's exactly right and it never softens anything.
Mega Pixel keeps aspect and uniformly scales so the frame's total pixel area equals megapixels. This is the mode for hitting a model's budget rather than its dimension.
Width x Height is exact, with crop_mode deciding how it gets there. crop scales to cover the target and centre-crops the overhang - no distortion. stretch resizes straight there and lets the aspect break. crop is the default and you should keep it unless you have a specific reason.
Every mode rounds the result to an even number of pixels, because odd frame dimensions get refused by some video encoders.
Inputs and outputs
The mode-specific fields all carry tooltips, and they all say which mode they belong to, which saves you guessing. The ones you'll actually touch:
images- the frame batch.mode- the five above; defaultLong side.upscale_method-lanczos(default) /bilinear/bicubic/area/nearest-exact. Lanczos for downscales and mild upscales,areaif you're shrinking hard and want it smooth.crop_mode-croporstretch, Width x Height mode only.
Optionally, get_name lets IMAGE data arrive wirelessly, and auto_set + setnode_name (default VideoResize) publish the outputs so the rest of the graph can grab them without wires.
Three outputs, and the last two are the reason I'd pick this over a ImageScale chain: images, plus width and height as INTs reflecting the actual post-rounding size. Wire those into the thing that expects to know the frame size and you stop hardcoding numbers that drift the moment you change a mode.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/designloves2/ComfyUI-TJ_NODE.git
# restart ComfyUI
Or ComfyUI Manager → Install Custom Nodes → search TJ_NODE. Nothing extra to download: this node has no model file and no special dependency. The pack's requirements.txt (llama-cpp-python, openpyxl, imageio, imageio-ffmpeg) is for its LLM and video-preview nodes - irrelevant here, though Manager installs it anyway.
When it goes wrong
The output size still isn't valid for your model. Even isn't always enough. LTX-2.3, for example, requires width and height divisible by 32, and off-grid values fail rather than round. If you're feeding a model with a hard grid, use Width x Height mode and type dimensions that are already on it.
Ratio mode changed the framing, not the size. Working as designed - that mode is crop-only. Use Long side or Mega Pixel if you actually wanted a resize.
Your encoder rejects the frames anyway. Check whether the odd-dimension guard is the wrong suspect: frame count constraints are their own thing (LTX wants count divisible by 8 plus 1), and no resize node can fix those.
Everything looks stretched. You're in stretch. Switch crop_mode back to crop.
Inputs (13)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | — | |
| mode | COMBO | Long side | 5 options: Long side, Short side, Ratio, Mega Pixel, Width x Height |
| upscale_method | COMBO | lanczos | 5 options: lanczos, bilinear, bicubic, area, nearest-exact |
| target_px | INT | 10808–16384 | Long side / Short side only — the target pixel length for that edge; the other edge follows to keep aspect. |
| ratio_w | INT | 161–64 | Ratio mode only — target aspect ratio's W part. Centre-crops at the source's own resolution, no scaling. |
| ratio_h | INT | 91–64 | Ratio mode only — target aspect ratio's H part. |
| megapixels | FLOAT | 1.000.01–64 | Mega Pixel mode only — uniform scale so the frame's pixel area matches this many megapixels, aspect kept. |
| target_width | INT | 12808–16384 | Width x Height mode only. |
| target_height | INT | 7208–16384 | Width x Height mode only. |
| crop_mode | COMBO | crop | Width x Height mode only. crop = scale to cover the target then centre-crop the overhang (no distortion). stretch = resize straight to the target (aspect not kept). |
| get_nameopt | STRING | (none) | — |
| auto_setopt | BOOLEAN | false | 켜면 출력들을 setnode_name 기반 이름으로 자동 Set 등록. |
| setnode_nameopt | STRING | VideoResize | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| images | IMAGE | — |
| width | INT | — |
| height | INT | — |