Dimensions from Prepare Info
The Width and Height Your Editor Actually Got
- prepare_info
- width
- height
Smart Photo Prepare picks an output size on your behalf - that's a feature, and it's also why you sometimes need to ask what it picked. This reader takes the typed preparation bundle and emits width and height as two plain INTs.
No widgets, no inputs beyond prepare_info, no pixel work. It reads the planned target dimensions; it does not re-run preparation or measure the tensor.
Why anyone wants this
Because ComfyUI is full of nodes that take a width and a height and nothing else, and a typed configuration bundle can't connect to an INT socket. That's the entire reason the Readers category exists - the pack went to typed buses so a node wouldn't have twenty outputs, and readers are how you get primitives back out at the one place you need them.
Concretely, you'll reach for these when:
- You need an empty latent or a conditioning canvas at the exact size of
prepared_image, and the downstream node wants numbers rather than a dimension socket. - You're feeding a plain upscaler or tile pipeline that needs to know its input size, especially on the Direct / No Editor path where the output size follows your crop and aspect instead of an editor tier.
- You want to log or assert the size. A note node, a filename, a sanity check that you really did get 2K out of Qwen 2.1 and not the 1 MP tier.
- You're comparing runs. Width and height are the fastest way to see that switching resolution policy changed what you got.
The values are the planned target - the same numbers prepared_image comes out at, including any padding, after the final resize. Note that on the Direct path there's no editor tier selection, so this is source-scale geometry.
Wiring
Smart Photo Prepare.prepare_info → Dimensions from Prepare Info.prepare_info
width, height → Primitive/EmptyLatent/whatever needs INTs
Both outputs are INT and both are always populated, so you don't need to branch. If a downstream node inverts the two - height-first - that's on you to keep straight, and it's the most common way to end up with a portrait render squashed into a landscape canvas.
The reader validates its input. If you wire in something that isn't a preparation result you'll get told to connect Smart Photo Prepare's info output rather than quietly reading zeroes. When the numbers look wrong, the order of investigation is: check the Input & Crop Config resolution policy, then the Active Editor Target (it decides which sizing table applies - a FireRed target near 1 MP versus Qwen 2.1's 2K tier is a big difference), then framing_tolerance_percent if two crops were close. Summary from Prepare Info's selection_reason field spells out which policy won, which is the reader to pair with this one when the size surprises you.
Install
Part of the pack; nothing separate.
cd ComfyUI/custom_nodes
git clone https://github.com/heyburns/PortraitUtils
/path/to/ComfyUI/venv/bin/python -m pip install -r PortraitUtils/requirements.txt
Then restart the ComfyUI server - ComfyUI Manager will offer the pack by name (PortraitUtils) if you'd rather click. Windows portable installs should run pip through python_embeded. The shared dependencies are numpy, Pillow, opencv-python-headless (exactly one OpenCV variant, they share the cv2 namespace) and tifffile.
If the node isn't in the menu under PortraitUtils/Photo Edit V2/Readers, the pack didn't import - read the startup console instead of reinstalling, since the fault is upstream of this reader. And if you're coming from 1.x: like the rest of the version-2 readers, this is a new ID, not a renamed old one, so saved workflows will show missing nodes until you swap it in.
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| prepare_info | PORTRAIT_PREPARATION_INFO_V2 | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| width | INT | — |
| height | INT | — |