public static class GamutMapBrings a colour that is outside a display's gamut into it, by CSS Color 4's binary search with local MINDE — reducing chroma while holding lightness and hue, rather than clipping channels.
Remarks
⚠ Per-channel clipping is not a cheaper version of this, it is a different answer. Clamping each channel to [0, 1] moves the hue: a vivid red runs out of red first and keeps whatever green and blue it had, so it clips towards orange. Reducing chroma at constant lightness and hue desaturates instead, which is the error a viewer forgives.
⚠ The destination is the display's gamut, not always sRGB. On a P3 panel oklch(0.7 0.3 30) is showable and must not be touched at all; mapping it to sRGB anyway throws away exactly the chroma the panel was bought for. This is why the repair belongs at presentation, where the swapchain's colour space is known, and why nothing earlier in the pipeline should clamp — see ToLinear.
Everything here is in linear sRGB primaries, including the results. A colour outside sRGB is carried as linear values outside [0, 1] — which is what VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT means, and what keeps the engine's working space unchanged. Map returns a colour still in those coordinates, but guaranteed to land inside [0, 1] once FromLinearSrgb rebases it onto the destination's primaries.
Implements CSS Color 4 §14.2.1-2. The specification now offers three algorithms — this one, EdgeSeeker, and a ray-trace variant — and lets an implementation pick among them; this is the one with reference implementations to check against, and the only one whose constants the prose pins down.
Fields and properties (2)
public const float JustNoticeableDifferenceOne just-noticeable difference in Oklab, as CSS Color 4 fixes it.
public const float SearchEpsilonWhere the chroma search stops narrowing.
Methods (7)
public static Vector3 FromLinearSrgb(Vector3 linear, ColorGamut gamut)Rebases a linear sRGB colour onto another gamut's primaries.
public static Vector3 ToLinearSrgb(Vector3 linear, ColorGamut gamut)Rebases a colour from a gamut's primaries back onto linear sRGB.
public static bool InGamut(Vector3 linear, ColorGamut gamut)Whether a colour is showable on a display with this gamut.
public static Vector3 Clip(Vector3 linear, ColorGamut gamut)Clamps a colour into a gamut channel by channel.
public static float DeltaEOk(Oklab left, Oklab right)The perceptual distance between two colours.
public static Vector3 Map(Vector3 linear, ColorGamut gamut)Brings a colour into a gamut, preserving lightness and hue.
public static Color4 Map(Color4 colour, ColorGamut gamut)Brings a colour into a gamut, preserving lightness, hue and alpha.
Used by (7)
- GamutMapTestsVixen.Core.Mathematics.Tests
- OkLchVixen.Ui.Controls.Advanced
- StyleValueParserVixen.Ui.Styling
- ThemeAndScannerTestsVixen.Ui.Styling.Utilities.Tests
- UiGamutTestsVixen.Ui.Tests
- UiGeometryBuilderVixen.Ui
- WideGamutTestsVixen.Ui.Styling.Tests