simulateCvd function
Simulates how color is perceived by a viewer with the given colour
vision deficiency type, returning the simulated colour.
Uses the physiologically-based model of Machado, Oliveira & Fairchild (2009) at full severity — see the citation on the matrix constants in this library. The pipeline is:
- decode the gamma-encoded sRGB channels to linear RGB,
- multiply by the deficiency matrix (defined in linear space),
- clamp to
[0, 1]and re-encode to sRGB.
Properties that follow from the model:
- CvdType.none is the identity — the input is returned unchanged.
- Achromatic colours (black, white, greys) are invariant under every deficiency type, because each matrix row sums to 1.
- The alpha channel is preserved untouched; simulation applies to the colour components only.
The sRGB decode/encode here uses the official sRGB transfer function
(IEC 61966-2-1, thresholds 0.04045 / 0.0031308). This intentionally
differs from relativeLuminance in the contrast module, which follows
WCAG 2.x's own published variant of the formula.
Implementation
Color simulateCvd(Color color, CvdType type) {
final m = switch (type) {
CvdType.none => null,
CvdType.protanopia => _protanopia,
CvdType.deuteranopia => _deuteranopia,
CvdType.tritanopia => _tritanopia,
};
if (m == null) return color;
final r = _srgbDecode(color.r);
final g = _srgbDecode(color.g);
final b = _srgbDecode(color.b);
final simR = clampDouble(m[0] * r + m[1] * g + m[2] * b, 0, 1);
final simG = clampDouble(m[3] * r + m[4] * g + m[5] * b, 0, 1);
final simB = clampDouble(m[6] * r + m[7] * g + m[8] * b, 0, 1);
return Color.from(
alpha: color.a,
red: _srgbEncode(simR),
green: _srgbEncode(simG),
blue: _srgbEncode(simB),
);
}