Auto: Tone & White Balance
A Lightroom Auto Button That Leaves Your Sunset Alone
- image
- image
- params_json
Most "auto levels" implementations share a flaw: they find the mean brightness of the image and drag it to mid-grey. That's fine for a snapshot of a wall and wrong for everything moody, everything high-key, and every sunset ever shot. Auto white balance has the same failure and it's worse, because a sunset is made of warm pixels - any algorithm that averages the image and calls the average a colour cast will neutralise the one thing you wanted.
Auto: Tone & White Balance (JHPixelProAutoTone) is the pack's take on Lightroom's Auto, and the interesting thing about it is how much machinery exists purely to not act. The author says it plainly: the constants are hand-tuned on test photos, deliberately not fitted to Adobe's Auto. The node doesn't claim to match Lightroom.
What it actually measures
Everything runs on a copy capped at 512 px on the long side, so the result is identical whether you feed it 2 MP or 50 MP. Each image in a batch is measured on its own.
Exposure comes from log-average luminance, steering toward a 12% key - deliberately a bit under mid-grey, so low-key shots stay low-key. A dark photo gets lifted at most +1 EV, capped so the brightest 0.5% doesn't clip more than half a stop. Bright photos are only darkened above a 65% key, because high-key is bright on purpose. And if 40% or more of the frame is near-white (product on white, blown studio background), only the rest of the picture - the subject - gets judged. Tiny corrections get skipped.
White balance uses only near-grey pixels, found iteratively so big uniform colour areas like skin never qualify. The correction is scaled by how many near-grey pixels there are and damped on top of that. A photo with no neutral objects gets little or no WB change, and that's intended, not a bug - go set Temp and Tint by hand in ColorLab.
Tone moves the 99.5th and 0.5th luma percentiles toward fixed targets for Whites/Blacks, and Highlights/Shadows follow how much of the frame is near clipping.
The inputs you'll touch
image, then strength (0–1) - 0 returns the original, and 0.5–0.8 is the honest starting point for anything you intend to finish by hand.
The optional switches are the interesting part: exposure, tone, white_balance and black_and_white. Turning white_balance off is the correct move for candlelight, tungsten interiors and golden hour. black_and_white converts with an automatic mix where brighter colour bands become brighter greys, which keeps colour contrast as tonal contrast instead of flattening everything.
max_wb_shift (0–100, default 50) is the finer-grained version of that switch: the largest Temp/Tint change white balance is allowed to make. Lower it and the correction gets timid instead of colour-cast-free.
The output that makes this more than a one-click filter
params_json is the applied settings, as ColorLab keys, including tone_engine = local and exposure_mode = linear. Wire it into a ColorLab params_json input and your sliders add on top of the automatic pass. Wire it into Apply ColorLab Preset and you've got a reusable grade.
That's the workflow: Auto Tone one representative frame, then reuse its settings across the shoot. Note it reports only the first image of a batch, so don't expect per-frame settings to come back out of a batch run.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/jetthuangai/ComfyUI-JH-PixelPro.git
cd ComfyUI-JH-PixelPro
pip install -r requirements.txt # the Python that runs ComfyUI
ComfyUI Manager users: search ComfyUI-JH-PixelPro, install, restart. Find the node at Add Node → ComfyUI-JH-PixelPro → color. Requirements are kornia>=0.7, mediapipe>=0.10.33, opencv-python-headless>=4.8, scipy>=1.10; PyTorch comes from ComfyUI. Roughly 1.5 s per 4K image and about 1 GB VRAM, so it's cheap enough to leave in a batch pipeline.
Where it goes wrong
- It's a starting point, not a grade. If you're feeding the result straight to a save node, you'll get a competent, slightly generic JPEG. Spend the ten minutes in ColorLab.
- "It didn't fix my colour cast." Probably no near-grey pixels to measure. Add a neutral reference or set Temp/Tint manually.
- Heavy-handed on portraits with a white background. That's exactly the near-white case above - the node judges the subject only, so a subject that's genuinely bright comes back barely changed. Not a bug.
- Sequencing. Straighten (Auto Upright) before this, so the measurement sees the final framing.
Worth knowing what kind of project this is: Apache-2.0, 64 nodes, actively released, thorough bilingual docs and a big test suite - and almost no discussion of it in the Reddit corpus, where the entire "PixelPro" search returns one unrelated browser extension. So there's no folklore to inherit. Judge it on your own photos: export a dozen, look at them small, and see whether the ones that survived are the ones you'd have graded the same way. That's the only test that matters for an auto anything.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | Photo to correct (each image of a batch is measured on its own). | |
| strength | FLOAT | 1.000–1 | 0 = original, 1 = full automatic correction. |
| exposureopt | BOOLEAN | true | Fix brightness. |
| toneopt | BOOLEAN | true | Set Whites, Blacks, Highlights, Shadows. |
| white_balanceopt | BOOLEAN | true | Remove colour casts using near-grey areas. |
| black_and_whiteopt | BOOLEAN | false | Convert to black and white with an automatic colour mix. |
| max_wb_shiftopt | FLOAT | 500–100 | Largest Temp/Tint change. Lower it for photos whose warm or cool light is intended (sunsets, candlelight). |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | The corrected image. |
| params_json | STRING | The settings that were applied (first image of a batch). Connect to a ColorLab's params_json to fine-tune them, or to Apply ColorLab Preset to reuse them. |