ComfyUI Node

Gamut Map

Roll off out-of-gamut colors instead of crushing them

By criskb·Created 7 months ago·Updated 5 months ago· 0
Gamut Map
  • image
  • mask
  • image
  • mask
  • gamut_map_info
settings_json{"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}

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.

CategoryMKRShift Nodes/Color/Finish

Inputs (3)

NameTypeDefaultDescription
imageIMAGE
settings_jsonSTRING{"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}
maskoptMASK

Outputs (3)

NameTypeDescription
imageIMAGE
maskMASK
gamut_map_infoSTRING