Saya Dynamic Near-4K Target · Preserve Ratio
From any image to a near-4K target that keeps its ratio
- image
- image
- target_width
- target_height
- model_factor
- target_megapixels
"Upscale to 4K" is never as simple as it sounds, because your image almost certainly isn't 16:9. Shove a 3:2 portrait into a fixed 3840×2160 and you either stretch it, crop it, or letterbox it. SayaNear4KTargetCalculator is the node that does the thinking instead: give it an image and a pixel budget, and it returns the dimensions that hit that budget while preserving the source's aspect ratio - snapped to multiples of 16 so the result plays nice with ComfyUI's latents and resize nodes.
The mechanism is more careful than a naive scale. It takes your target pixel count and the source ratio, computes the ideal width/height, then searches a window of candidate sizes around it (24 steps of 16 in each direction) and scores every candidate on two axes: how far the ratio drifted from the source, weighted eight times heavier, and how far the total pixels landed from your budget. Composition first, exact pixels second. That weighting is the whole point - an upscale that changes 16:9 into 16.2:9 has failed at the one thing you asked it to preserve. What comes out is the candidate that keeps the picture looking like the same picture, at roughly the size you asked for.
Inputs are just image and target_pixels (default 8,294,400 - that's 3840×2160, the near-4K budget the display name points at). The outputs are what you'll actually wire:
- target_width / target_height (INT) - the exact destination dims.
- model_factor (FLOAT) - the upscale ratio the model upscaler needs: the larger of width/height divided by the source, clamped to a sane 1.0–4.0 range.
- target_megapixels (FLOAT) - how many megapixels the target really is.
- image - the original passes straight through, so the node can sit in the middle of a chain without a reroute.
Here's the intended split, and it's the part that makes the outputs make sense: model upscalers do best on a factor, not a hard size, and many of them (the WLSH-style "Upscale by Factor with Model" node this pack's demo workflow uses, for one) accept a float factor. So you wire model_factor into the model upscale at whatever clean multiple it lands on, then do a final exact resize to target_width × target_height - the calculator's own source calls it "the exact Lanczos fit directly after it" - to land precisely on the calculated target. model_factor is deliberately clamped so you're not asking a 4× model to do 7× in one jump; beyond 4×, break it into stages.
One honest naming note, because it'll save you confusion: SayaNear4KTargetCalculator is the same code as SayaUpscaleTargetCalculator. The registry keeps both ids pointing at one implementation - this is the older, "near-4K" name from before the pack's final-upscale presets existed, kept alive so old workflows load. Same inputs, same outputs, same defaults. If you're adding a fresh node, the pack lists it as "Saya Dynamic Upscale Target"; this page is what you get when an old workflow or a search surfaces the legacy name.
Install is shared with the whole pack - Manager search saya-comfy-couple-plus, or clone into custom_nodes and restart:
cd ComfyUI/custom_nodes
git clone https://github.com/alphaziod/saya-comfy-couple-plus
Only numpy/Pillow as extra deps; no downloads. The pack is explicitly work-in-progress, so re-save workflows after updates and keep backups if this node is load-bearing in yours.
It's a tiny node that answers a genuinely fiddly question - "what dimensions actually get me near 4K without wrecking my composition" - and answers it with an algorithm instead of your eyeball.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| target_pixels | INT | 829440065536–268435456 | — |
Outputs (5)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| target_width | INT | — |
| target_height | INT | — |
| model_factor | FLOAT | — |
| target_megapixels | FLOAT | — |