The floor sat at 0.25 MP, so 16:9's cheapest entry was 768x432 — and that one is K2-only (432 % 32 = 16), leaving 1024x576 as the smallest H3-legal 16:9 in the list. An audio-only H3 render wants 512x288, the n=1 lattice point at alignment 32, where the video canvas is pure overhead. Dropping PRESET_MIN_MP alone re-picks the geometric thinning and silently drops labels — 3:2 1152x768 and 1920x1280 among them — which breaks saved workflows, since the label string is what a graph stores. Raising PRESET_MAX_ENTRIES to 11 in the same step absorbs that: 79 -> 87 entries with every existing label still present and still pointing at the same size. The six entries beyond 512x288 / 288x512 are lattice points the old 9-entry cap had been skipping over. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K1sGVWw5KU3GD7CrhdZR7M
457 lines
18 KiB
Markdown
457 lines
18 KiB
Markdown
# ComfyUI-ResolutionTools
|
||
|
||
Resolution maths for latent-space models, done exactly.
|
||
|
||
Three nodes, no dependencies:
|
||
|
||
| Node | Does |
|
||
|---|---|
|
||
| **Resolution Preset** | pick a known-good resolution from a list — start here |
|
||
| **Resolution Selector (Real MP)** | aspect ratio + real megapixels → grid-aligned width/height, ratio held exact |
|
||
| **Align Resolution to Grid** | snap an arbitrary size onto the grid (1920×1080 → 1920×1088) |
|
||
|
||
```
|
||
Resolution Preset
|
||
┌────────────────────────────────────────────────────┐
|
||
│ preset 16:9 · 2048 × 1152 · 2.36 MP · K2+H3+SDXL │
|
||
└────────────────────────────────────────────────────┘
|
||
↳ width 2048 height 1152 megapixels 2.36 label "2048x1152"
|
||
```
|
||
|
||
## Usage
|
||
|
||
Pick a preset, wire `width` and `height` into whatever takes dimensions. That's the
|
||
whole thing:
|
||
|
||
```
|
||
Resolution Preset ──┬── width ──▶ Empty Latent · width
|
||
└── height ─▶ Empty Latent · height
|
||
```
|
||
|
||
Either empty-latent node works. `EmptySD3LatentImage` is the nominally correct one for
|
||
Krea 2 (`[B, 16, H//8, W//8]`, matching its 16-channel Wan21 format), but the legacy
|
||
4-channel `EmptyLatentImage` is fine too: `comfy/sample.py` runs
|
||
`fix_empty_latent_channels`, which detects an all-zero latent and repeats it out to the
|
||
model's channel count. Same for the MiniMax H3 nodes — feed `width`/`height` straight
|
||
into `MiniMax H3 Image to Video`.
|
||
|
||
`megapixels` and `label` are there when useful and cost nothing left unconnected.
|
||
`label` gives `"2048x1152"`, handy wired into a `filename_prefix` so saved files carry
|
||
their resolution.
|
||
|
||
### Three concrete pipelines
|
||
|
||
**Krea 2 stills, delivered to a 1920×1080 screen** — pick `16:9 · 2048 × 1152`, then
|
||
downscale once at the very end:
|
||
|
||
```
|
||
Resolution Preset 16:9 · 2048 × 1152 · 2.36 MP · K2+H3+SDXL
|
||
│ width, height
|
||
▼
|
||
EmptySD3LatentImage → KSampler → VAEDecode
|
||
▼
|
||
Upscale Image lanczos · 1920 × 1080 · crop disabled
|
||
▼
|
||
Save Image
|
||
```
|
||
|
||
**MiniMax H3 video** — same front end into the H3 nodes. `2048 × 1152` if you want the
|
||
crop-free downscale to 1080p; `1536 × 864` if you want to stay nearer H3's 1.03 MP
|
||
native canvas and accept a ×1.25 upscale. See
|
||
[Delivering to a fixed screen size](#delivering-to-a-fixed-screen-size) for the
|
||
trade-off, which is about 5 dB of preserved detail.
|
||
|
||
**Krea 2 Edit character reference** — pick a portrait preset and feed it at native
|
||
resolution, with **no** `Upscale Image` on that branch:
|
||
|
||
```
|
||
Resolution Preset 9:16 · 1152 × 2048 · 2.36 MP · K2+H3+SDXL
|
||
│ width, height
|
||
▼
|
||
(generate) → VAEEncode → ReferenceLatent → Edit Model Reference Method
|
||
```
|
||
|
||
Reference and generation resolutions are independent — the DiT gives each reference its
|
||
own slot in the positional ids, so a portrait reference conditioning a landscape
|
||
generation is the intended design. Do not downscale a reference to your delivery size:
|
||
`ReferenceLatent` never resizes, so whatever you hand it is what conditions the model,
|
||
and 1080 is not a multiple of 16 anyway.
|
||
|
||
### When to use the other two nodes
|
||
|
||
**Resolution Selector (Real MP)** — a ratio or size the preset list doesn't carry: a
|
||
custom ratio, an exact pixel budget, or 21:9 at 2352×1008 (on grid 16, while the 21:9
|
||
presets use grid 64). It's an alternative to the preset node, not a stage after it;
|
||
chaining them is meaningless, since it takes a ratio and a budget rather than
|
||
dimensions.
|
||
|
||
**Align Resolution to Grid** — dimensions you didn't choose. An img2img or ControlNet
|
||
source, or an upscale chain where multiplying by 1.5 lands off-grid.
|
||
|
||
## Why
|
||
|
||
### 1. "Megapixels" usually isn't megapixels
|
||
|
||
ComfyUI's built-in Resolution Selector computes `megapixels * 1024 * 1024`. That's
|
||
**mebipixels** — every value you type is inflated 4.86% in area. Ask for 2.36 MP at
|
||
9:16 and you get 1184×2096 = 2.48 real MP.
|
||
|
||
This node uses `megapixels * 1_000_000`. Ask for 2.36 and you get 2.36.
|
||
|
||
**So convert before you copy a number out of a model's docs.** A megapixel figure in
|
||
someone else's guide is almost always in the built-in node's unit; multiply by 1.049 to
|
||
get the value to type here. ComfyUI's own MiniMax H3 tutorial, for instance, says to set
|
||
Megapixels to `0.98` — that is **1.03 real MP**. With `exact_ratio` on, the lattice
|
||
usually absorbs an error that small; with it off, 4.86% is exactly the margin you miss
|
||
by. At 16:9 and `alignment = 32`, typing 1.03 gives 1344×768 and typing 0.98 gives
|
||
1312×736.
|
||
|
||
Worth noticing what that setting produces in the first place: 1344×768 is **7:4**
|
||
(1.750), not the 16:9 (1.778) it is offered under. It reaches H3's documented canvas
|
||
only because the two axes rounded apart — see below. The exact-16:9 lattice at
|
||
`alignment = 32` is `512n × 288n`, which steps 1024×576 → 1536×864 with nothing in
|
||
between, so there is no on-ratio ~1 MP frame to be had; pick a row instead.
|
||
|
||
### 2. Rounding each axis independently drifts the aspect ratio
|
||
|
||
That same 1184×2096 has a ratio of 0.5649. True 9:16 is 0.5625. Both axes were
|
||
individually snapped to a multiple of 16, and the ratio fell between the cracks.
|
||
|
||
With `exact_ratio` on (the default), this node solves on the **lattice of sizes that
|
||
are simultaneously grid-aligned and exactly on-ratio**. For a reduced ratio `a:b` and
|
||
alignment `m`, those are exactly `(a·L·n, b·L·n)` where
|
||
|
||
```
|
||
L = lcm(m / gcd(a, m), m / gcd(b, m))
|
||
```
|
||
|
||
so it picks `n = round(sqrt(target_px / (a·b·L²)))`. For 9:16 at m=16 the lattice is
|
||
`144n × 256n`, and n=8 gives **1152×2048** — exact 9:16, on the grid, 2.36 MP.
|
||
|
||
Turn `exact_ratio` off to get the old independent-rounding behaviour when you'd rather
|
||
hit the area target precisely and don't care about a hair of ratio drift.
|
||
|
||
### 3. Getting alignment wrong bands the bottom of your image
|
||
|
||
A latent-space DiT reaches pixels through two reductions:
|
||
|
||
```
|
||
pixels ──/ VAE spatial downscale ──> latent ──/ DiT patch size ──> tokens
|
||
```
|
||
|
||
Both axes must be multiples of `vae_downscale × patch_size`:
|
||
|
||
| Models | Alignment | |
|
||
|---|---|---|
|
||
| Krea 2, Flux, SD3, Qwen-Image, Wan | **16** | 8 × 2 |
|
||
| MiniMax H3 | **32** | 16 × 2 |
|
||
| SDXL, SD1.5 (UNet, 3 downsample stages) | **64** | universally safe |
|
||
|
||
Miss it and `comfy.ldm.common_dit.pad_to_patch_size` pads the latent up to the patch
|
||
grid using **circular** padding — the pad row is a wrapped copy of the *top* of the
|
||
image. That fabricated row gets folded into the same patch token as the real bottom
|
||
row, a combination the model never saw in training, so the final latent row decodes to
|
||
garbage: a band along the bottom edge, 8 px tall on Krea 2, 16 px on H3. Padding is
|
||
only ever appended, so the artifact is always bottom/right, never top/left.
|
||
|
||
This is why 1920×1080 bands on Krea 2 (1080/8 = 135 latent rows, odd) and 1920×1088
|
||
doesn't (1088/8 = 136, even). The built-in selector defaults `multiple` to 8, which
|
||
walks you straight into it.
|
||
|
||
## Reference resolutions
|
||
|
||
All values below are **real** megapixels. If you're migrating from a table computed
|
||
with the built-in selector, every label in it is ~4.86% low — a row marked "2.0 MP"
|
||
there is really 2.09.
|
||
|
||
### Exact-ratio tables (`exact_ratio = true`)
|
||
|
||
These are the *complete* set of true-16:9 grid-aligned resolutions. There is nothing
|
||
valid between the rows: the lattice is `256n × 144n` at alignment 16 and
|
||
`512n × 288n` at alignment 32. Type the listed megapixels and you get that row back.
|
||
|
||
Krea 2 — `alignment = 16`:
|
||
|
||
| megapixels | Aspect | Output (alignment=16) |
|
||
|---|---|---|
|
||
| 0.15 | 16:9 | 512 x 288 |
|
||
| 0.33 | 16:9 | 768 x 432 |
|
||
| 0.59 | 16:9 | 1024 x 576 |
|
||
| 0.92 | 16:9 | 1280 x 720 |
|
||
| 1.33 | 16:9 | 1536 x 864 |
|
||
| 1.81 | 16:9 | 1792 x 1008 |
|
||
| 2.36 | 16:9 | 2048 x 1152 |
|
||
| 2.99 | 16:9 | 2304 x 1296 |
|
||
| 3.69 | 16:9 | 2560 x 1440 |
|
||
| 4.46 | 16:9 | 2816 x 1584 |
|
||
|
||
MiniMax H3 — `alignment = 32`:
|
||
|
||
| megapixels | Aspect | Output (alignment=32) |
|
||
|---|---|---|
|
||
| 0.15 | 16:9 | 512 x 288 |
|
||
| 0.59 | 16:9 | 1024 x 576 |
|
||
| 1.33 | 16:9 | 1536 x 864 |
|
||
| 2.36 | 16:9 | 2048 x 1152 |
|
||
| 3.69 | 16:9 | 2560 x 1440 |
|
||
| 5.31 | 16:9 | 3072 x 1728 |
|
||
|
||
Five rows to 4 MP is genuinely all there is on a 32-grid — which is why none of the
|
||
commonly circulated H3 resolution tables are actually 16:9.
|
||
|
||
### Area-target tables (`exact_ratio = false`)
|
||
|
||
For when you want a specific pixel budget more than a perfect ratio. Each axis is
|
||
rounded independently, so the ratio drifts a little.
|
||
|
||
Krea 2 — `alignment = 16`:
|
||
|
||
| megapixels | Aspect | Output (alignment=16) |
|
||
|---|---|---|
|
||
| 0.2 | 16:9 | 592 x 336 |
|
||
| 0.3 | 16:9 | 736 x 416 |
|
||
| 0.4 | 16:9 | 848 x 480 |
|
||
| 0.5 | 16:9 | 944 x 528 |
|
||
| 0.6 | 16:9 | 1040 x 576 |
|
||
| 0.7 | 16:9 | 1120 x 624 |
|
||
| 0.8 | 16:9 | 1200 x 672 |
|
||
| 0.9 | 16:9 | 1264 x 704 |
|
||
| 1.0 | 16:9 | 1328 x 752 |
|
||
| 1.2 | 16:9 | 1456 x 816 |
|
||
| 1.4 | 16:9 | 1584 x 880 |
|
||
| 1.6 | 16:9 | 1680 x 944 |
|
||
| 1.8 | 16:9 | 1792 x 1008 |
|
||
| 2.0 | 16:9 | 1888 x 1056 |
|
||
| 2.25 | 16:9 | 2000 x 1120 |
|
||
| 2.5 | 16:9 | 2112 x 1184 |
|
||
| 2.75 | 16:9 | 2208 x 1248 |
|
||
| 3.0 | 16:9 | 2304 x 1296 |
|
||
| 3.25 | 16:9 | 2400 x 1360 |
|
||
| 3.5 | 16:9 | 2496 x 1408 |
|
||
| 3.75 | 16:9 | 2576 x 1456 |
|
||
| 4.0 | 16:9 | 2672 x 1504 |
|
||
|
||
MiniMax H3 — `alignment = 32`:
|
||
|
||
| megapixels | Aspect | Output (alignment=32) |
|
||
|---|---|---|
|
||
| 0.2 | 16:9 | 608 x 320 |
|
||
| 0.3 | 16:9 | 736 x 416 |
|
||
| 0.4 | 16:9 | 832 x 480 |
|
||
| 0.5 | 16:9 | 928 x 544 |
|
||
| 0.6 | 16:9 | 1024 x 576 |
|
||
| 0.7 | 16:9 | 1120 x 640 |
|
||
| 0.8 | 16:9 | 1184 x 672 |
|
||
| 0.9 | 16:9 | 1280 x 704 |
|
||
| 1.0 | 16:9 | 1344 x 736 |
|
||
| 1.2 | 16:9 | 1472 x 832 |
|
||
| 1.4 | 16:9 | 1568 x 896 |
|
||
| 1.6 | 16:9 | 1696 x 960 |
|
||
| 1.8 | 16:9 | 1792 x 992 |
|
||
| 2.0 | 16:9 | 1888 x 1056 |
|
||
| 2.25 | 16:9 | 1984 x 1120 |
|
||
| 2.5 | 16:9 | 2112 x 1184 |
|
||
| 2.75 | 16:9 | 2208 x 1248 |
|
||
| 3.0 | 16:9 | 2304 x 1312 |
|
||
| 3.25 | 16:9 | 2400 x 1344 |
|
||
| 3.5 | 16:9 | 2496 x 1408 |
|
||
| 3.75 | 16:9 | 2592 x 1440 |
|
||
| 4.0 | 16:9 | 2656 x 1504 |
|
||
|
||
Ratio drift is under 1% for most Krea 2 rows, but gets bad on H3 at the low end —
|
||
6.9% at 0.2 MP, where a 32 px step is a large fraction of a 320 px axis. Below about
|
||
0.6 MP on H3, use the exact lattice instead.
|
||
|
||
### Other ratios at ~2.36 MP (Krea 2, `alignment = 16`)
|
||
|
||
| megapixels | Aspect | Output (alignment=16) |
|
||
|---|---|---|
|
||
| 2.36 | 1:1 | 1536 x 1536 |
|
||
| 2.36 | 16:9 | 2048 x 1152 |
|
||
| 2.36 | 9:16 | 1152 x 2048 |
|
||
| 2.22 | 3:2 | 1824 x 1216 |
|
||
| 2.22 | 2:3 | 1216 x 1824 |
|
||
| 2.24 | 4:3 | 1728 x 1296 |
|
||
| 2.24 | 3:4 | 1296 x 1728 |
|
||
| 2.37 | 21:9 | 2352 x 1008 |
|
||
| 2.37 | 9:21 | 1008 x 2352 |
|
||
|
||
### Picking a row
|
||
|
||
**Krea 2** — the official envelope is a 1K–2K long edge, so 2.36 MP (2048×1152) is the
|
||
top of sanctioned territory. The 2.99 and 3.69 rows are extrapolation: expect detail
|
||
repetition rather than sharper eyes.
|
||
|
||
**MiniMax H3** — the native canvas is a 768 short edge, 768×1344 ≈ 1.03 MP
|
||
(`BASE_SHORT_EDGE` / `MAX_PIXELS` in `comfy_extras/nodes_minimax_h3.py`), and 1344×768
|
||
is the node default. 1.33 MP (1536×864) is a mild ~29% stretch and the highest row
|
||
worth running by default. 2.36 MP is 2.3× the trained area and 3.69 MP is 3.6×; motion
|
||
coherence degrades before sharpness improves.
|
||
|
||
## Delivering to a fixed screen size
|
||
|
||
If your output has to land on a fixed canvas — a 1920×1080 game screen, for instance —
|
||
generate on the exact-ratio lattice and **downscale**. Do not generate at the delivery
|
||
size and crop.
|
||
|
||
1920×1080 is exactly 16:9, and so is every row of the lattice, so the whole table
|
||
resizes onto it with no crop at all:
|
||
|
||
| Generate | MP | → 1920×1080 | Crop |
|
||
|---|---|---|---|
|
||
| 1280 × 720 | 0.92 | ×1.5 upscale | none |
|
||
| 1536 × 864 | 1.33 | ×1.25 upscale | none |
|
||
| 1792 × 1008 | 1.81 | ×1.0714 upscale | none |
|
||
| 2048 × 1152 | 2.36 | ×0.9375 downscale | none |
|
||
| 2304 × 1296 | 2.99 | ×0.8333 downscale | none |
|
||
| 2560 × 1440 | 3.69 | ×0.75 downscale | none |
|
||
| 1920 × 1088 | 2.09 | x:1.0 / y:0.9926 | **8 px** |
|
||
|
||
1920×1088 is the only entry needing a crop, because it is the only one that isn't 16:9
|
||
(1.7647). Generating over-size and downscaling is also **supersampling** — you get free
|
||
anti-aliasing on hair, eyelashes and fabric that a 1:1 render plus a trim never gives
|
||
you. 2048×1152 is the pick for Krea 2; 2560×1440 → ×0.75 is an unusually clean resample
|
||
(4 pixels become 3) if you want more of it.
|
||
|
||
### Which filter
|
||
|
||
Measured on a zone plate (frequencies rising toward the edges, so aliasing shows up as
|
||
error) against a properly antialiased reference:
|
||
|
||
| Filter | RMSE, 2048×1152 → 1920×1080 | RMSE, 2560×1440 → 1920×1080 |
|
||
|---|---|---|
|
||
| **lanczos** | **0.00298** | **0.00325** |
|
||
| bicubic | 0.00577 | 0.00365 |
|
||
| bilinear | 0.00650 | 0.00418 |
|
||
| area | 0.04291 | 0.03082 |
|
||
| nearest-exact | 0.04198 | 0.03787 |
|
||
|
||
**Use `lanczos`.** Two caveats:
|
||
|
||
- **`area` is a trap.** The usual advice is "area is the downscale filter," and here it
|
||
is ~10× worse than bicubic. That advice only holds for large reductions. A box filter
|
||
at a non-integer factor near 1 averages one input pixel for some outputs and two for
|
||
others — uneven weighting, visible as blotchiness.
|
||
- **`lanczos` quantises to 8-bit.** `comfy/utils.py` routes it through PIL via
|
||
`Image.fromarray(np.clip(255. * ..., 0, 255).astype(np.uint8))`. Irrelevant for 8-bit
|
||
delivery (PNG / WebP / VP9), but if you keep a 16-bit master, save it *before* the
|
||
scale node. To stay in float through the resize, use `bicubic` — second best, small
|
||
gap.
|
||
|
||
### Use `Upscale Image`, not `Upscale Image By`
|
||
|
||
Pin the delivery size, not the scale factor. `ImageScaleBy` computes
|
||
`round(dim * scale_by)` and then calls the same `common_upscale` as `ImageScale`, so the
|
||
pixels are identical — but its `scale_by` widget has `step: 0.01`, and the rounded
|
||
factors are wrong for most of the table:
|
||
|
||
| Source | typed at step 0.01 | result |
|
||
|---|---|---|
|
||
| 1792 × 1008 | 1.07 | 1917 × 1079 ✗ |
|
||
| 2048 × 1152 | 0.94 | 1925 × 1083 ✗ |
|
||
| 2304 × 1296 | 0.83 | 1912 × 1076 ✗ |
|
||
| 2816 × 1584 | 0.68 | 1915 × 1077 ✗ |
|
||
|
||
Feeding the factor from a full-precision float node avoids that, but buys nothing:
|
||
`ImageScale` at `1920 × 1080` is exact by construction, needs no extra node, and is
|
||
correct for *every* lattice row without edits — whereas a hardcoded factor is correct
|
||
for exactly one source resolution and goes silently stale the moment you change the
|
||
megapixel target.
|
||
|
||
The lattice already did the work upstream by making the source exactly 16:9. `0.9375`
|
||
is just what `1920/2048` happens to equal; it isn't a number you need to carry around.
|
||
|
||
### Wiring it up
|
||
|
||
Graphs for the common cases are under [Usage](#usage). The delivery-side detail:
|
||
|
||
`Upscale Image` handles a `[B,H,W,C]` video batch frame by frame, but if you are dumping
|
||
a PNG sequence and encoding with ffmpeg anyway, fold the resize into that pass instead —
|
||
it avoids an intermediate 8-bit round trip and ffmpeg's lanczos is full precision:
|
||
|
||
```bash
|
||
ffmpeg -framerate 24 -i raw_%05d.png \
|
||
-vf "scale=1920:1080:flags=lanczos,format=yuv420p" \
|
||
-c:v libvpx-vp9 -crf 28 -b:v 0 -row-mt 1 \
|
||
out.webm
|
||
```
|
||
|
||
24 fps matches H3's internal `FPS = 24`.
|
||
|
||
### One simplification
|
||
|
||
Set **`alignment = 32` for everything.** 32 is a multiple of 16, so every size it
|
||
produces is legal on Krea 2 *and* MiniMax H3 — one configuration for a whole project
|
||
instead of tracking which model needs which grid. The lattice is coarser, but at 16:9
|
||
the useful rows are all still there (1024×576, 1536×864, 2048×1152, 2560×1440), and
|
||
2048×1152 comes out identical either way.
|
||
|
||
## Nodes
|
||
|
||
### Resolution Preset
|
||
|
||
One combo of 87 known-good resolutions. Every entry is exactly on its aspect ratio and
|
||
on the patch grid, so there is nothing to compute and nothing to look up.
|
||
|
||
**Inputs** — `preset`, formatted `ratio · width × height · real MP · compatible models`.
|
||
The trailing tag comes from the resolution's divisibility, not a hand-kept table:
|
||
|
||
| Tag | Grid | Models |
|
||
|---|---|---|
|
||
| `K2` | 16 | Krea 2, Flux, SD3, Qwen-Image, Wan |
|
||
| `K2+H3` | 32 | the above, plus MiniMax H3 |
|
||
| `K2+H3+SDXL` | 64 | the above, plus SDXL / SD1.5 — universally safe |
|
||
|
||
**Outputs** — `width`, `height`, `megapixels`, `label`.
|
||
|
||
The list is **generated from the lattice at import time**, never hand-maintained, so it
|
||
cannot drift from what `Resolution Selector (Real MP)` produces. Per ratio it uses the
|
||
coarsest grid that still offers at least six sizes: fine-lattice ratios like 1:1 (where
|
||
L=16, so every 16 px is legal) would otherwise contribute a hundred near-identical
|
||
entries, and the coarse grid lands them on canonical sizes — 512, 768, 1024, 1536, 2048
|
||
— instead. Coarse-lattice ratios like 16:9 fall through to grid 16 and keep their full
|
||
useful set.
|
||
|
||
The list spans 0.15 to 4.3 MP. The bottom end is there for runs where the canvas is
|
||
overhead rather than output — an audio-only MiniMax H3 render, say, where `16:9 · 512 ×
|
||
288` is the smallest exact 16:9 the model's 32 px grid admits.
|
||
|
||
Why a list and not a number: with `exact_ratio` on, the valid outputs *are* a discrete
|
||
lattice. A continuous megapixel input advertises precision that does not exist, and
|
||
pushes the lookup table out of the node and into your head (or a sticky note next to
|
||
the graph). Reach for `Resolution Selector (Real MP)` when you need a ratio or a size
|
||
this list does not carry — 21:9 at exactly 2352×1008, say, which falls on grid 16 while
|
||
the 21:9 presets use grid 64.
|
||
|
||
### Resolution Selector (Real MP)
|
||
|
||
**Inputs** — `aspect_ratio` (11 presets + Custom), `megapixels` (real, 10⁶),
|
||
`alignment` (default 16), `exact_ratio` (default on), `custom_w` / `custom_h` (advanced,
|
||
for the Custom ratio).
|
||
|
||
**Outputs** — `width`, `height`, `megapixels` (what it actually produced), `label`
|
||
(`"1152x2048"`, useful for filename prefixes).
|
||
|
||
### Align Resolution to Grid
|
||
|
||
**Inputs** — `width`, `height`, `alignment`, `mode` (`round` / `up` / `down`).
|
||
|
||
**Outputs** — `width`, `height`, `changed` (true if anything was off-grid), `label`.
|
||
|
||
Use `up` when you must not lose framing, `down` when you must not exceed a budget.
|
||
|
||
## Install
|
||
|
||
Via ComfyUI-Manager, or:
|
||
|
||
```bash
|
||
cd ComfyUI/custom_nodes
|
||
git clone https://github.com/dreevelle/ComfyUI-ResolutionTools
|
||
```
|
||
|
||
No dependencies, no restart quirks — it's pure stdlib maths.
|
||
|
||
## License
|
||
|
||
MIT
|