a tool for shared writing and social publishing
1// X = <negative/positive number with/without decimal places>
2// before/after a comma, 0 or more whitespaces are allowed
3// - hsb(X, X%, X%)
4// - hsba(X, X%, X%, X)
5const HSB_REGEX =
6 /hsb\(([-+]?\d+(?:.\d+)?\s*,\s*[-+]?\d+(?:.\d+)?%\s*,\s*[-+]?\d+(?:.\d+)?%)\)|hsba\(([-+]?\d+(?:.\d+)?\s*,\s*[-+]?\d+(?:.\d+)?%\s*,\s*[-+]?\d+(?:.\d+)?%\s*,\s*[-+]?\d(.\d+)?)\)/;
7
8export function parseHSBToRGB(color: string) {
9 let m: RegExpMatchArray | null;
10 if ((m = color.match(HSB_REGEX))) {
11 const [h, s, b, a] = (m[1] ?? m[2])
12 .split(",")
13 .map((n) => Number(n.trim().replace("%", "")));
14 let hue = normalizeHue(h);
15 let saturation = s / 100;
16 let brightness = b / 100;
17 let fn = (n: number, k = (n + hue / 60) % 6) =>
18 brightness - saturation * brightness * Math.max(Math.min(k, 4 - k, 1), 0);
19 let [red, green, blue] = [
20 Math.round(fn(5) * 255),
21 Math.round(fn(3) * 255),
22 Math.round(fn(1) * 255),
23 a,
24 ];
25 return `rgb(${red}, ${green}, ${blue})`;
26 }
27}
28
29export function normalizeHue(hue: number) {
30 if (hue === 360) {
31 return hue;
32 }
33
34 return ((hue % 360) + 360) % 360;
35}