parseModelColor function
Parses an xcolor model specification: \color[rgb]{0.1,0.2,0.3}.
Supported models: rgb (0–1), RGB (0–255), HTML (hex), gray
(0–1), cmyk (0–1, converted as xcolor converts), named (a colour
name, defined giving a formula's own). Of a list of models
(rgb/cmyk with 1,0,0/0,1,1,0) the first is used. Returns null if
the value is invalid.
Implementation
LatexColor? parseModelColor(
String model,
String value, {
LatexColor? Function(String name)? defined,
}) {
if (model.contains('/')) {
model = model.substring(0, model.indexOf('/')).trim();
if (value.contains('/')) value = value.substring(0, value.indexOf('/'));
}
if (model == 'named') return parseColor(value, defined: defined);
final parts = value.split(',').map((s) => s.trim()).toList();
double? unit(String s) {
final v = double.tryParse(s);
return v == null || v < 0 || v > 1 ? null : v;
}
int byte(double v) => (v * 255).round();
switch (model) {
case 'rgb':
if (parts.length != 3) return null;
final c = parts.map(unit).toList();
if (c.contains(null)) return null;
return LatexColor.fromARGB(0xFF, byte(c[0]!), byte(c[1]!), byte(c[2]!));
case 'RGB':
if (parts.length != 3) return null;
final c = parts.map(int.tryParse).toList();
if (c.any((v) => v == null || v < 0 || v > 255)) return null;
return LatexColor.fromARGB(0xFF, c[0]!, c[1]!, c[2]!);
case 'HTML':
if (!RegExp(r'^[0-9a-fA-F]{6}$').hasMatch(value.trim())) return null;
return LatexColor(0xFF000000 | int.parse(value.trim(), radix: 16));
case 'gray':
if (parts.length != 1) return null;
final g = unit(parts[0]);
if (g == null) return null;
return LatexColor.fromARGB(0xFF, byte(g), byte(g), byte(g));
case 'cmyk':
if (parts.length != 4) return null;
final c = parts.map(unit).toList();
if (c.contains(null)) return null;
// xcolor: cmyk → cmy is min(1, c + k), then rgb = 1 − cmy.
final k = c[3]!;
int channel(double v) => byte(1 - math.min(1, v + k));
return LatexColor.fromARGB(
0xFF,
channel(c[0]!),
channel(c[1]!),
channel(c[2]!),
);
}
return null;
}