Scale from Config
Hand a plain FLOAT to somebody else's upscaler
- finish_config
- scale
What it's for
Your upscale factors live in a Finish & Run Config bundle. Most upscalers are not PortraitUtils nodes and want a plain FLOAT - an "upscale by" widget or a scale input. Bundles don't connect to primitive sockets, so something has to unpack it.
Scale from Config does exactly that: finish_config in, scale out, and a selector telling it which of the two factors you want. No maths, no state, no side effects.
Inputs and outputs
Required: finish_config (PORTRAIT_FINISH_CONFIG_V2) and scale, a dropdown with two options - initial_upscale or final_upscale. Default is final_upscale. That's the entire node. Output: scale (FLOAT).
The two values come from the config as 0.1–100. If you need them, they're 2.0 and 4.0 out of the box - the default shape being "one moderate pass to get the pixels, one heavier pass for detail."
Where it fits
Keep the decision in the config and the consumer wherever it already is:
Finish & Run Config ──> Scale from Config [initial_upscale] ─ FLOAT ─> first upscaler
└─> Scale from Config [final_upscale] ─ FLOAT ─> second upscaler
Two readers, two consumers, one place to change the numbers. If you find yourself editing three widgets across two nodes to change a 2x into a 3x, this node is the fix - and it's a much smaller fix than a context-bus overhaul.
Worth being clear about what a scale factor does and doesn't buy you. If your upscaler's job is more pixels - an ESRGAN model, a Lanczos resize - then 4x is a deterministic multiplier and this reader is exactly right. If its job is more invented detail - a tile-ControlNet pass, a detail model - then the factor is closer to a hint, and pushing it past what the model handles well gives you softness, not detail. And in both cases, most of these numbers only make sense as a final step: an upscale early in the chain means every later operation runs on 4x the pixels for no gain.
Where people get burned
Feeding this into the wrong socket. It emits a FLOAT; if your upscaler's scaling widget takes a plain number, perfect. If it exposes a fixed model choice or an enum of 2x/4x, you're better off setting that node's own widget and skipping the reader - a converter isn't going to invent a dropdown for you.
The other one is subtler: because the value arrives as a wire, the upscaler's own widget disappears or gets overridden, depending on the node. If a scale change doesn't seem to take effect, check whether the bundle is actually connected - a disconnected reader input doesn't error, it just isn't there.
And don't try to route finish_config into a generic primitive node. It's a typed bundle; only PortraitUtils readers and consumers take it.
Related readers
The whole family is one input, one output, zero decisions:
- Seed from Config - the run seed as an
INT. - Crop Prompt from Config -
subject_maskas aSTRING. - Edit Prompt from Config - one of the four edit/stitch prompts.
- Outpaint Prompt from Config - the outpainting prompt.
- Save Info from Source - filename and output directory from the loader.
Install
Part of PortraitUtils. ComfyUI Manager → search PortraitUtils (publisher heyburns, GPLv3), or:
cd ComfyUI/custom_nodes
git clone https://github.com/heyburns/PortraitUtils
/path/to/ComfyUI/venv/bin/python -m pip install -r PortraitUtils/requirements.txt
Install into ComfyUI's Python environment - numpy, Pillow, opencv-python-headless and tifffile, with only one OpenCV variant - then restart the ComfyUI server. The pack supplies no upscaler weights; bring your own ESRGAN or detail model.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| finish_config | PORTRAIT_FINISH_CONFIG_V2 | — | |
| scale | COMBO | final_upscale | 2 options: initial_upscale, final_upscale |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| scale | FLOAT | — |