Nodes/comfyui-moonpack/Proportional Dimension
ComfyUI Node

Proportional Dimension

Resize math that doesn't butcher your aspect ratio — and snaps to the divisor your model needs

By moonwhaler·Created about a year ago·Updated 11 days ago· 16
Proportional Dimension
  • from_image
  • width
  • height
  • shortest_side
  • longest_side
  • scale
width1440
height1024
target_size480
target_sideshortest
orientationauto
divisible_by1
roundingnearest
resize_modetarget_side
megapixels1.00

You've typed 768 and 512 into an EmptyLatentImage widget one too many times, and at some point you asked the obvious question: why am I doing division in my head? Proportional Dimension is the answer - it takes a source size, scales it so one chosen side hits a target, snaps both dimensions to a divisor, and hands you the result as clean integers plus the scale factor.

The practical reason this matters more than it sounds: diffusion models are picky. SDXL wants dimensions that are multiples of 8, Wan wants its own divisors, and upscaling at a random non-snapped resolution is a fast way to get garbage or an OOM. This node does the arithmetic so the numbers you feed the graph are always model-friendly.

The inputs that matter

The core set is small, and most of it you'll leave at defaults:

  • width and height - your source dimensions. Defaults are 1440x1024, but you'll usually overwrite these from a Dimension From Image node or similar.
  • target_size - the pixel size for the chosen side. Default 480.
  • target_side - shortest or longest. Pick shortest to upscale so the smaller side hits the target (great for taking a tiny image up); pick longest to cap the bigger side (great for keeping a big image inside a budget).
  • orientation - auto keeps the source orientation; landscape/portrait force one and swap as needed; square just produces target_size x target_size and ignores target_side.
  • divisible_by and rounding - the reason you're here. Set divisible_by to 8 (or 64, or whatever your model wants) and rounding to nearest, floor, or ceil. Floor guarantees the result is ≤ the ideal size, ceil guarantees ≥. For latent-size safety, floor is your friend.

There's also an optional from_image input: wire an IMAGE tensor in and it reads the source dimensions from the image instead of the widgets. That's the version you use in reusable workflows.

The outputs

width and height are the obvious ones - straight into an EmptyLatentImage or an upscale node. Then there are three that cost nothing but earn their keep: shortest_side and longest_side (the scaled smaller and larger dimensions), and scale (a FLOAT, the ratio of output to input). scale is the sneaky useful one - feed it into a denoise or strength widget and the whole graph scales proportionally with the image.

Installing it

Standard MoonPack install:

cd ComfyUI/custom_nodes
git clone https://github.com/moonwhaler/comfyui-moonpack.git

Or ComfyUI Manager → search MoonPack → install, then restart. Found under MoonPack/image. No models, no extra Python dependencies - the pack ships clean.

The one trap

The orientation/target_side combo reads like a menu of options, but if you just want "same aspect, capped at a reasonable size," the fastest setup is target_side = longest, divisible_by = 8, rounding = floor. Everything else is for the cases you'll hit once a month. Don't overthink it - the defaults are sane, and the outputs are there for you to inspect rather than guess.

CategoryMoonPack/image

Inputs (10)

NameTypeDefaultDescription
widthINT14401–16384Original width in pixels.
heightINT10241–16384Original height in pixels.
target_sizeINT4801–16384Desired size for the selected side. Only used when resize_mode is 'target_side'.
target_sideCOMBOshortestWhich side target_size applies to. 'shortest' upscales the smaller side; 'longest' caps the larger side. Only used when resize_mode is 'target_side'.
orientationCOMBOautoForce output orientation. 'auto' keeps source orientation. 'landscape'/'portrait' swap width/height when source doesn't match. 'square' produces target_size x target_size (ignores target_side).
divisible_byINT11–1024Snap output dimensions to a multiple of this value (1 = no snapping).
roundingCOMBOnearestHow to snap to the divisor. 'floor' guarantees output ≤ ideal; 'ceil' guarantees ≥.
resize_modeCOMBOtarget_side'target_side' uses target_size/target_side above. 'megapixels' uses the megapixels field instead and ignores target_size/target_side.
megapixelsFLOAT1.000.01–100Target total megapixels (width x height / 1e6), aspect ratio preserved. Only used when resize_mode is 'megapixels'.
from_imageoptIMAGEOptional: read width/height from an IMAGE tensor instead of the widgets.

Outputs (5)

NameTypeDescription
widthINT
heightINT
shortest_sideINT
longest_sideINT
scaleFLOAT