Nodes/saya-comfy-couple-plus/Saya Dynamic Upscale Target · Preserve Ratio
ComfyUI Node

Saya Dynamic Upscale Target · Preserve Ratio

Turn a pixel budget into width and height your image can live with

By alphaziod·Created 3 months ago·Updated about 15 hours ago· 3
Saya Dynamic Upscale Target · Preserve Ratio
  • image
  • image
  • target_width
  • target_height
  • model_factor
  • target_megapixels
target_pixels8294400

You know the endgame resolution you want in megapixels. The question that always follows is "but what exact width and height?" - because 4K is defined for 16:9 and your image is 3:2, or square, or 9:16, and every answer that ignores the ratio ruins the composition. SayaUpscaleTargetCalculator is the node that answers it properly: it takes your image and a pixel budget and hands back the dimensions that land you at that budget without changing the aspect ratio, snapped to multiples of 16.

It's the canonical node in the pack's final-upscale pair - the other half being SayaUpscalePresetModelLoader, which picks the preset and loads the model. That pairing is how the workflow reads in practice: the preset loader sets the budget (say the 4K "equivalent" at 8,294,400 pixels) and hands it over as target_pixels; this node takes that budget plus your actual image and computes the real destination. If you're not using the preset loader, you can type any pixel budget directly - the default is that same 8,294,400 (3840×2160), and it's a plain INT field, so nothing stops you from targeting 12 megapixels if your card can take it.

The math is where the "preserve ratio" promise gets real. It computes the ideal width/height for the budget, then searches a window of 16-multiple candidates around it and scores each on two criteria: ratio drift from the source (weighted heavily) and pixel error against the budget. It picks the candidate that keeps the picture shaped like the same picture while getting as close as it can to your target size. The output of that search is what lands on the sockets:

  • target_width / target_height (INT) - the exact destination dimensions.
  • model_factor (FLOAT) - the required upscale ratio, clamped to 1.0–4.0: the larger of width/height over the source, so an upscaler model can be told a single sane factor.
  • target_megapixels (FLOAT) - what the target actually totals.
  • image - the source passes through untouched, keeping the node inline.

The two-stage upscale pattern this is built for: model upscalers want a factor, and ComfyUI's WLSH-style "Upscale by Factor with Model" nodes take a float - so you wire model_factor into the model upscale pass, then follow it with an exact Lanczos resize to target_width × target_height to hit the precise calculated size. The factor is clamped to 4× for a reason; if your source needs more than 4× to reach the target, stage it instead of asking one pass to invent that much.

And the naming footnote that keeps confusing people: this node used to be called the "Near-4K" calculator, and the pack still registers SayaNear4KTargetCalculator as an alias pointing at this same code - same inputs, same outputs - so older workflows that reference the near-4K name keep loading. If a search drops you on that page, you're reading about the same node.

Install is the pack-wide story: ComfyUI Manager search saya-comfy-couple-plus, or

cd ComfyUI/custom_nodes
git clone https://github.com/alphaziod/saya-comfy-couple-plus

then restart. Extra deps are numpy and Pillow only, and nothing downloads. The pack is explicit that it's work-in-progress, so re-save workflows after updates and keep backups if this node drives your final pass.

It won't make an upscaler's output better, but it fixes the class of problem that makes otherwise-fine upscales look wrong: ending up at 3832×2148 because you eyeballed it, or at a ratio that's subtly off. That's a quiet, valuable job.

CategorySaya/Scaling

Inputs (2)

NameTypeDefaultDescription
imageIMAGE
target_pixelsINT829440065536–268435456

Outputs (5)

NameTypeDescription
imageIMAGE
target_widthINT
target_heightINT
model_factorFLOAT
target_megapixelsFLOAT