defmodule GitGud.Badges.Oklch do
@moduledoc """
oklch to sRGB, and WCAG contrast.
The themes in `assets/css/app.css` are written in oklch, which a
browser resolves itself. A badge that leaves the browser (a PNG, an
SVG on someone else's site) needs concrete sRGB, so the conversion
happens here, once, at compile time (`GitGud.Badges.Palette`).
Björn Ottosson's oklab matrices; colors outside sRGB are clipped per
channel, which is what browsers did before CSS Color 4 gamut mapping
and is close enough for the few saturated tokens it touches.
"""
@type lin :: {float(), float(), float()}
@doc "Linear sRGB channels, each clipped to 0..1, for `oklch(l% c h)`."
@spec to_linear(number(), number(), number()) :: lin()
def to_linear(l_pct, c, h) do
l = l_pct / 100
rad = h * :math.pi() / 180
a = c * :math.cos(rad)
b = c * :math.sin(rad)
l_ = :math.pow(l + 0.3963377774 * a + 0.2158037573 * b, 3)
m_ = :math.pow(l - 0.1055613458 * a - 0.0638541728 * b, 3)
s_ = :math.pow(l - 0.0894841775 * a - 1.2914855480 * b, 3)
{
clip(4.0767416621 * l_ - 3.3077115913 * m_ + 0.2309699292 * s_),
clip(-1.2684380046 * l_ + 2.6097574011 * m_ - 0.3413193965 * s_),
clip(-0.0041960863 * l_ - 0.7034186147 * m_ + 1.7076147010 * s_)
}
end
@doc "`#rrggbb` for linear channels."
@spec hex(lin()) :: String.t()
def hex({r, g, b}) do
"#" <> Enum.map_join([r, g, b], &byte/1)
end
@doc "WCAG relative luminance of linear channels."
@spec luminance(lin()) :: float()
def luminance({r, g, b}), do: 0.2126 * r + 0.7152 * g + 0.0722 * b
@doc "WCAG contrast ratio between two luminances, 1.0 to 21.0."
@spec contrast(float(), float()) :: float()
def contrast(y1, y2), do: (max(y1, y2) + 0.05) / (min(y1, y2) + 0.05)
defp clip(v), do: v |> max(0.0) |> min(1.0)
defp byte(v) do
encoded = if v <= 0.0031308, do: 12.92 * v, else: 1.055 * :math.pow(v, 1 / 2.4) - 0.055
(encoded * 255)
|> round()
|> Integer.to_string(16)
|> String.downcase()
|> String.pad_leading(2, "0")
end
end
neiam
/gitgud
Git Gud
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
1
Log in to mark this repository.
2.0 KiB · text
History
0d6bdf0