Auto Adjust (Levels/Tone/Color)
Photoshop's Auto Levels, Tone, and Color — recreated as a ComfyUI node
- image
- IMAGE
If you've ever edited a photo, you've hit the "Auto" buttons in Photoshop's Levels and Color dialogs and wondered why the raw tool doesn't exist in ComfyUI. It does now. AutoAdjustNode is a faithful reimplementation of Photoshop's Auto Levels / Auto Tone / Auto Color: it looks at the histogram, clips the dead shadows and blown highlights, and stretches the rest to fill the range - plus optional color correction. No model involved, no weights, no VRAM load. It's a pre-processor that makes your input look the way a photo editor expects it to before it ever hits a diffusion model.
It does this in three independent passes, each with its own toggle:
auto_levels- the classic black/white point stretch.levels_shadow_clip_pctandlevels_highlight_clip_pct(defaults 0.1) say how much of the histogram to clip at each end. 0.1% is gentle; bump to 0.5–1% for murky scans that need a firmer hand.levels_gamma_normalizeoptionally re-centers the midtone after the stretch so you don't shift overall brightness.auto_tone- the same idea but aimed at tonal balance, in either Per-channel mode (each RGB channel stretched independently, stronger contrast, slight color risk) or Monochromatic mode (stretch luma only, safer).auto_color- neutralizes color cast.snap_neutral_midtonesforces near-gray midtones to true gray, which is great for fixing yellowed scans but can fight intentional warm grades, so leave it off unless you need it.
The two toggles you'll actually touch on every job: precision and flip_horizontal. precision is Exact vs Histogram (fast). Exact computes true percentiles via torch.quantile; Histogram uses torch.histc bins - visually identical in almost every case and noticeably faster on big images, so that's a reasonable default. flip_horizontal is a whole-pass mirror, which reads oddly until you realize you're processing source scans that were placed face-down and need flipping before any of the other adjustments make sense.
The single output is IMAGE - just a stretched version of what came in. Because the math runs per-frame on the tensor, it handles batches fine and is cheap enough to stick right after a loader on every run.
Install
ComfyUI Manager → search "PortraitUtils", or:
cd ComfyUI/custom_nodes
git clone https://github.com/heyburns/PortraitUtils
Restart after cloning. It only needs torch + numpy, both already in ComfyUI's environment, so there's nothing extra to download.
Common issues
- Colors shift in Per-channel tone mode - expected behavior, not a bug. Each channel stretches independently so saturation drifts; switch
tone_modeto Monochromatic if you want the contrast without the tint. - Image looks hazy or crushed - your clip percentages are too big or too small. Start at 0.1/0.1, watch a log widget, and only move one knob at a time. These are percent-of-histogram values, and small changes go a long way.
- It fights your grade - this is a correction node, not a style node. Run it early in the graph on the source photo, not after you've deliberately set a mood.
Want to apply the exact same settings to multiple branches? That's what AutoColorConfigNode is for - the pack's README shows wiring one config node into several Auto Adjust blocks so a whole multi-model branch gets identical treatment. For one-off use, the node's defaults are sane, which is rare for a tool this fiddly.
Inputs (13)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| precision | COMBO | Exact | 2 options: Histogram (fast), Exact |
| auto_levels | BOOLEAN | true | — |
| levels_shadow_clip_pct | FLOAT | 0.100–5 | — |
| levels_highlight_clip_pct | FLOAT | 0.100–5 | — |
| levels_gamma_normalize | BOOLEAN | false | — |
| auto_tone | BOOLEAN | true | — |
| tone_mode | COMBO | Per-channel | 2 options: Per-channel, Monochromatic |
| tone_shadow_clip_pct | FLOAT | 0.100–5 | — |
| tone_highlight_clip_pct | FLOAT | 0.100–5 | — |
| auto_color | BOOLEAN | true | — |
| snap_neutral_midtones | BOOLEAN | false | — |
| flip_horizontal | BOOLEAN | false | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |