Gamut Map
Roll off out-of-gamut colors instead of crushing them
- image
- mask
- image
- mask
- gamut_map_info
Every AI image has a few pixels that are more saturated or brighter than the display can show. Most pipelines deal with this by hard-clipping - the color slams to pure red or pure white, you get that ugly flat posterized band, and nobody's happy. x1GamutMap is the finish node that fixes that properly: it compresses out-of-range colors with a soft rolloff instead of cutting them off. If your workflow is "generate → grade → send somewhere," this is the safety net that stops the last step from turning your highlights to mush.
It's part of MKRShift Nodes by Cris K B, under MKRShift Nodes/Color/Finish - and it's the inverse half of the pack's analysis node x1GamutWarning, which shows you the problem; this fixes it.
How it works
The mechanism is a soft compression in color space. compression (default 0.25) controls how hard out-of-range values are pulled back toward the safe range, and rolloff (default 0.35) shapes how they're pulled: high rolloff gives a long, gentle curve that starts compressing well before the limit, so the transition is invisible; low rolloff bites closer to the edge, faster. The difference from clipping is everything - clipped red turns to flat pure red, rolled-off red turns to a slightly-deeper red that still has shape.
Two protect knobs keep the compression from wrecking what's already good: highlight_protect (default 0.25) stops the highlights from losing their punch, and neutral_protect (default 0.35) keeps neutral greys from picking up a color cast as neighboring saturated pixels get compressed into them - a real failure mode of naive gamut mapping, and a thoughtful default to have. saturation is a final global adjustment, preserve_luma (default on) keeps brightness stable while the colors compress, and mix blends the whole transform.
The inputs that matter
Inside the settings_json:
compression- how much out-of-range color gets pulled back (default 0.25; raise if you see clipping).rolloff- how soft the compression curve is (default 0.35).highlight_protect/neutral_protect- the "don't wreck the good stuff" knobs.preserve_luma- keeps brightness fixed while colors compress (default on).
Optional mask input with mask_feather / invert_mask, plus outputs image, mask, and a gamut_map_info string.
Installing it
cd ComfyUI/custom_nodes
git clone https://github.com/criskb/MKRShift_Nodes
Restart ComfyUI, or install via ComfyUI Manager (search MKRShift_Nodes). No requirements.txt, no models, no keys.
The take
The workflow that makes this earn its place: run x1GamutWarning on your image, see the red/white problem zones, then drop x1GamutMap after your grade at default settings and re-check - the warning zones should fade without the image flattening. It's the kind of node you don't notice when it works, which is the point. Where people get burned: it's not a cure for over-saturation baked into a model - if everything's neon, compression at 0.25 is a band-aid and you should actually pull saturation. But for the "my output clips on the delivery screen" problem, this is the right tool.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| settings_json | STRING | {"compression":0.25,"rolloff":0.35,"saturation":1.0,"highlight_protect":0.25,"neutral_protect":0.35,"preserve_luma":true,"mix":1.0,"mask_feather":12.0,"invert_mask":false} | — |
| maskopt | MASK | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| mask | MASK | — |
| gamut_map_info | STRING | — |