Suggest clamped chroma for out-of-gamut OKLCH
This commit is contained in:
parent
3a0e6a9b7f
commit
a881ba4f77
2 changed files with 41 additions and 21 deletions
|
@ -1,8 +1,8 @@
|
|||
{ lib }:
|
||||
|
||||
let
|
||||
inherit (builtins) add floor mapAttrs split stringLength;
|
||||
inherit (lib) concatLines fixedWidthNumber fold isList max removeSuffix splitString throwIfNot toHexString;
|
||||
inherit (builtins) add all attrValues floor mapAttrs split stringLength;
|
||||
inherit (lib) concatLines fixedWidthNumber fold isList max removeSuffix splitString throwIf throwIfNot toHexString;
|
||||
inherit (lib.strings) replicate;
|
||||
inherit (import <nix-math> { inherit lib; }) cos pi polynomial pow sin;
|
||||
|
||||
|
@ -39,6 +39,14 @@ let
|
|||
];
|
||||
in
|
||||
rec {
|
||||
findHighest = accept: resolution: low: high:
|
||||
if high - low < resolution then
|
||||
throwIfNot (accept low) "Lower bound ${toString low} fails acceptance test" low
|
||||
else
|
||||
let half = low + (high - low) * 0.5; in
|
||||
if accept half then findHighest accept resolution half high
|
||||
else findHighest accept resolution low half;
|
||||
|
||||
frame = color: text:
|
||||
let
|
||||
lines = splitString "\n" (removeSuffix "\n" text);
|
||||
|
@ -52,7 +60,11 @@ rec {
|
|||
(color "└───${pad "─" ""}───┘")
|
||||
]);
|
||||
|
||||
oklchToRgb = { l, c, h }:
|
||||
oklchToCss = { l, c, h }: "oklch(${toString l} ${toString c} ${toString h})";
|
||||
|
||||
oklchToRgb = target:
|
||||
let
|
||||
toLinearRgb = { l, c, h }:
|
||||
let
|
||||
# Adapted from https://drafts.csswg.org/css-color-4/#color-conversion-code
|
||||
a = c * cos (h * pi / 180);
|
||||
|
@ -62,16 +74,25 @@ rec {
|
|||
long = pow (l + 0.3963377774 * a + 0.2158037573 * b) 3;
|
||||
medium = pow (l - 0.1055613458 * a - 0.0638541728 * b) 3;
|
||||
short = pow (l - 0.0894841775 * a - 1.2914855480 * b) 3;
|
||||
linear = {
|
||||
rgb = {
|
||||
r = 4.0767416621 * long - 3.3077115913 * medium + 0.2309699292 * short;
|
||||
g = -1.2684380046 * long + 2.6097574011 * medium - 0.3413193965 * short;
|
||||
b = -0.0041960863 * long - 0.7034186147 * medium + 1.7076147010 * short;
|
||||
};
|
||||
oetf = l':
|
||||
throwIfNot (0 <= l' && l' <= 1) "oklch(${toString l} ${toString c} ${toString h}) is not representable in sRGB"
|
||||
(if l' > 0.0031308 then 1.055 * (pow124 l') - 0.055 else 12.92 * l');
|
||||
in
|
||||
mapAttrs (_: oetf) linear;
|
||||
if all (u: 0 <= u && u <= 1) (attrValues rgb) then rgb else null;
|
||||
|
||||
# Adapted from https://bottosson.github.io/posts/colorwrong/#what-can-we-do%3F
|
||||
oetf = u: if u > 0.0031308 then 1.055 * (pow124 u) - 0.055 else 12.92 * u;
|
||||
|
||||
inGamut = c: toLinearRgb (target // { inherit c; }) != null;
|
||||
clamped = target // { c = findHighest inGamut 0.0000005 0 0.37; };
|
||||
|
||||
linearRgb = toLinearRgb target;
|
||||
in
|
||||
throwIf (linearRgb == null)
|
||||
"Not representable in sRGB\n Target: ${oklchToCss target}\n Clamped: ${oklchToCss clamped}"
|
||||
(mapAttrs (_: oetf) linearRgb);
|
||||
|
||||
printableLength = text: fold add 0 (map (v: if isList v then 0 else stringLength v) (split "\\[[^m]*m" text));
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ let
|
|||
inherit (lib) concatLines imap0 mapAttrsRecursive mapAttrsToList nameValuePair;
|
||||
inherit (import ./lib.nix { inherit lib; }) oklchToRgb rgbToHex round;
|
||||
|
||||
# TODO: Automatically clamp to sRGB
|
||||
dark = c: c // { l = 0.35; c = if c.c == 0 then 0 else 0.060; };
|
||||
dim = c: c // { l = 0.50; c = if c.c == 0 then 0 else 0.150; };
|
||||
contrast-minimum = c: c // { l = c.l + 0.25 * (if c.l < 0.5 then 1 else - 1); };
|
||||
|
|
Loading…
Reference in a new issue