Pixel Constrained Scaler
The scaler that only does math — and saves your VRAM doing it
- image
- image_passthrough
- constrained_width
- constrained_height
- constrained_aspect_ratio
- original_aspect_ratio
Pixel Constrained Scaler does not resize your image. Read that again, because it's the whole trick: it's a calculator with an image input. You feed it a picture, it works out what width and height you should resize to so you stay under a hard megapixel cap while keeping the aspect ratio, and it hands you the numbers plus the untouched image. Then you plug those numbers into an actual resize node. It exists because "just feed the big image in" is exactly how ComfyUI workflows OOM - video models especially will happily try to process a 4K still and eat your whole VRAM.
The author's own pitch is image-to-image and image-to-video, and that's the honest use case. It's also a neat fit for the workflow the upscaling crowd keeps rediscovering: downscale a soft source before you run a generative upscaler, because there's no detail at full resolution to recover anyway. This node gives you a clean way to enforce that "never exceed N megapixels" rule without hand-computing sizes.
How the math works
The logic is straightforward, and the code spells it out in cases:
- If the input is already over the megapixel cap and you didn't ask to scale down, it shrinks to the cap, preserving aspect ratio.
- If the input is under the cap, it tries applying your
scaling_factor- but if that would blow past the cap, it pulls back down. - If you set
scaling_factorunder 1.0, that's an explicit downscale, and it always wins - it applies to the original before any clamping. - Everything gets rounded to your
multiple_ofand clamped to your min/max resolution bounds.
It handles batches (it reads the tensor shape, so a whole video batch gets one consistent target size) and it'll print a Notice: line to your console when the cap silently trims your requested scale - which is genuinely helpful debugging, not noise.
The inputs that matter
You only really touch three of these:
max_megapixels- the hard ceiling in millions of pixels. The default 2.36 MP is 1536×1536, which is right at the top of where a lot of SDXL-era and current models stay coherent. This is the OOM guard.scaling_factor- how much to scale relative to the current image (1.0 = no change, 2.0 = double, 0.5 = halve). The cap takes priority when the original is already too big.multiple_of- rounds the result so dimensions land on 8 or 64, which your model's VAE and a lot of node packs want. Default 8 is usually fine; set 64 for Flux-style pipelines.
min_res and max_res are safety rails for extreme aspect ratios. The image input is just analyzed, never touched.
The outputs and how to wire them
Five outputs. image_passthrough is your original image, byte for byte. constrained_width and constrained_height are the numbers you actually want - wire those into an ImageScale (or a latent-scale / empty-latent-size node) to do the real work. constrained_aspect_ratio and original_aspect_ratio are informational; grab them if you want to compare how far the constraints pushed you.
Install
Clone it into custom_nodes:
cd ComfyUI/custom_nodes
git clone https://github.com/neonr-0/ComfyUI-PixelConstrainedScaler.git
Then restart ComfyUI. It's also on the Comfy registry, so ComfyUI Manager should find it by searching "ComfyUI-PixelConstrainedScaler" - the easy route. There are no dependencies, no model downloads, nothing heavy. The entire node is one file of pure Python math.
Gotchas
The classic miss is wiring image_passthrough straight into your KSampler and wondering why nothing changed. The node only computes - you have to wire the width/height into a resize. If you hit a ValueError, it's almost always a bad config: max_res must be greater than min_res, and multiple_of must be at least 2. And one real edge case from the code: if you set min_res so high that even the minimum dimensions exceed your megapixel cap, the min/max clamps take priority and the cap quietly loses - don't set min_res anywhere near the square root of your cap.
It's a small, single-purpose node, and that's fine. There's no AI in the "scaler" - no key, no API, no models - which makes it about as safe a custom node as this ecosystem offers.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | Input image to analyze for resolution constraints | |
| min_res | INT | 256 | Minimum allowed dimension (width/height) in pixels |
| max_res | INT | 2048256–8192 | Maximum allowed dimension (width/height) in pixels |
| max_megapixels | FLOAT | 2.4 | Maximum allowed resolution in megapixels (e.g., 2.3 = 2.3 million pixels) |
| scaling_factor | FLOAT | 1.50.1–4 | Additional scaling factor (1.0 = no change, 2.0 = double size). Megapixel limit takes priority when original image is larger than the cap. |
| multiple_of | INT | 8 | Ensure dimensions are multiples of this number (8, 64, etc) |
Outputs (5)
| Name | Type | Description |
|---|---|---|
| image_passthrough | IMAGE | — |
| constrained_width | INT | — |
| constrained_height | INT | — |
| constrained_aspect_ratio | FLOAT | — |
| original_aspect_ratio | FLOAT | — |