simulateCvd function

Color simulateCvd(
  1. Color color,
  2. CvdType type
)

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:

  1. decode the gamma-encoded sRGB channels to linear RGB,
  2. multiply by the deficiency matrix (defined in linear space),
  3. 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),
  );
}