Nodes/ComfyUI-EsesImageEffectLevels/Eses Image Effect Levels
ComfyUI Node

Eses Image Effect Levels

Photoshop's Levels dialog, dragged into your node graph

By quasiblob·Created about a year ago·Updated about a year ago· 42
Eses Image Effect Levels
  • image
  • mask
  • adjusted_image
  • adjusted_mask
  • IMAGE
  • MASK
preset
channel
all_levels_json{"rgb": {"black_point": 0.0, "white_point": 1.0, "mid_point": 1.0, "output_black": 0, "output_white": 255}, "r": {"black_point": 0.0, "white_point": 1.0, "mid_point": 1.0, "output_black": 0, "output_white": 255}, "g": {"black_point": 0.0, "white_point": 1.0, "mid_point": 1.0, "output_black": 0, "output_white": 255}, "b": {"black_point": 0.0, "white_point": 1.0, "mid_point": 1.0, "output_black": 0, "output_white": 255}, "mask": {"black_point": 0.0, "white_point": 1.0, "mid_point": 1.0, "output_black": 0, "output_white": 255}}
auto_levelsfalse
auto_colorfalse
auto_sensitivity0.0020

If you've generated with a distilled or turbo model you know the look: flat, milky, like the contrast got dragged into a well. Most people "fix" it by chaining a few color-correction nodes together, or just save a slightly-off image and move on. Eses Image Effect Levels is the alternative - Photoshop's Levels dialog dropped into a single ComfyUI node, with a live histogram rendered right on the node body. You drag sliders, the preview updates, and the whole adjustment rides along inside the workflow JSON. No node spaghetti.

It sits in the post-process stretch of your graph, alongside the usual suspects (WAS Node Suite covers color correction as a toolbox of utility nodes, but those aren't interactive; this one is). It also works on masks, not just images - handy for tuning a blurry or soft-edged mask before it feeds an inpainting pass.

How it works. Every channel gets its own level set: black point, white point, mid point, and output black/white. There are five of them - the combined RGB composite, then Red, Green, and Blue individually, then a separate one for the mask. On execution, the Python side builds a 256-entry lookup table per channel and applies it with PIL's point(): each of the 256 tones gets remapped from the input range to the output range, then hit with a gamma curve where the mid point is 1/gamma. Order matters: RGB composite first, then per-channel, then re-merge. The README says "GPU-accelerated PyTorch," and the tensors do round-trip through torch, but the real work is a lookup table - which is exactly why it feels instant. The node forces a re-run on every execution (its IS_CHANGED returns NaN), so dragging a slider recomputes immediately, and the JS pushes a preview plus histogram data back over the websocket. It's a clever little loop.

The inputs that matter. The dropdowns are what you'll actually touch:

  • channel - which channel the sliders edit: RGB, Red, Green, Blue, or Mask.
  • preset - starts as None plus three shipped presets (blue, green, red), and grows once you save your own.

The visible sliders (Black, Mid, White, Output Black, Output White) aren't formal inputs - the node draws them itself and writes straight into all_levels_json, which is the one required field you'll basically never edit by hand. It's how your tweaks survive a page reload. The hidden auto_levels and auto_color booleans are one-shot triggers behind the "Set Auto Levels" and "Set Auto Color" buttons: they fire the queue, compute optimal black/white points from the histogram, and write the results back. auto_sensitivity (default 0.002) controls how aggressive that auto-detect is - roughly the fraction of pixels clipped off each end of the histogram. Lower is punchier, higher is gentler.

Both image and mask are optional inputs. Outputs: adjusted_image (IMAGE) and adjusted_mask (MASK), plus untouched passthroughs of the originals - handy if you want to keep the pre-adjustment version around for a blend or an A/B.

Installing it. No models, no requirements.txt, no hidden dependencies - just PyTorch, which you already have:

cd ComfyUI/custom_nodes
git clone https://github.com/quasiblob/ComfyUI-EsesImageEffectLevels.git

Restart ComfyUI and the node appears under Eses Nodes/Image Adjustments. ComfyUI Manager finds it if you search the pack title.

Gotchas. Two worth knowing. First, the license isn't MIT: quasiblob's "My ComfyUI Nodes License" allows free personal use, but forbids rebranding, code reuse, bundling, and redistributing anywhere but the original repo. Don't plan to fork or vendor this one. Second, your saved presets live as JSON files in the pack's own presets_levels folder - which means a ComfyUI Manager update of the pack can clobber them. Your workflow keeps the actual state either way, but back up that folder if your presets are precious.

One more honest note: it's a single-image-time tool. Each frame does tensor→numpy→PIL conversions, so feeding it a 100-image batch works but is wasteful - it shines when you're adjusting one hero image before saving, not filtering a dataset.

CategoryEses Nodes/Image Adjustments

Inputs (8)

NameTypeDefaultDescription
presetCOMBO4 options: None, blue, green, red
channelCOMBO5 options: RGB, Red, Green, Blue, Mask
all_levels_jsonSTRING{"rgb": {"black_point": 0.0, "white_point": 1.0, "mid_point": 1.0, "output_black": 0, "output_white": 255}, "r": {"black_point": 0.0, "white_point": 1.0, "mid_point": 1.0, "output_black": 0, "output_white": 255}, "g": {"black_point": 0.0, "white_point": 1.0, "mid_point": 1.0, "output_black": 0, "output_white": 255}, "b": {"black_point": 0.0, "white_point": 1.0, "mid_point": 1.0, "output_black": 0, "output_white": 255}, "mask": {"black_point": 0.0, "white_point": 1.0, "mid_point": 1.0, "output_black": 0, "output_white": 255}}
auto_levelsBOOLEANfalse
auto_colorBOOLEANfalse
auto_sensitivityFLOAT0.00200.0001–0.05
imageoptIMAGE
maskoptMASK

Outputs (4)

NameTypeDescription
adjusted_imageIMAGE
adjusted_maskMASK
IMAGEIMAGE
MASKMASK