Skip to content

Instantly share code, notes, and snippets.

@facelessuser
Last active March 8, 2023 05:14
Show Gist options
  • Save facelessuser/8f54cb27ce0f2c9403a2665af137c9f2 to your computer and use it in GitHub Desktop.
Save facelessuser/8f54cb27ce0f2c9403a2665af137c9f2 to your computer and use it in GitHub Desktop.
Lines of Confusion
# pragma: init
from coloraide import Color as Base
from coloraide.cat import WHITES
from coloraide.spaces import Space
from coloraide import algebra as alg
from coloraide.types import Vector
from coloraide.channels import Channel
from coloraide import Color as Base
class LMS(Space):
"""The LMS class."""
BASE = "srgb-linear"
NAME = "lms"
SERIALIZE = ("--lms",)
CHANNELS = (
Channel("l", 0.0, 1.0),
Channel("m", 0.0, 1.0),
Channel("s", 0.0, 1.0)
)
CHANNEL_ALIASES = {
"long": "l",
"medium": "m",
"short": "s"
}
WHITE = WHITES['2deg']['D65']
LRGB_TO_LMS = [
[0.178824041258, 0.4351609057000001, 0.04119349692],
[0.034556423182, 0.27155382458, 0.038671308360000003],
[0.000299565576, 0.0018430896, 0.01467086136]
]
LMS_TO_LRGB = [
[8.094435598032371, -13.050431460496926, 11.672058453917323],
[-1.0248505586646686, 5.401931309674973, -11.361471490598712],
[-0.03652974715933318, -0.412162807001268, 69.35132423820858]
]
def to_base(self, coords: Vector) -> Vector:
"""To XYZ."""
return alg.dot(self.LMS_TO_LRGB, coords, dims=alg.D2_D1)
def from_base(self, coords: Vector) -> Vector:
"""From XYZ."""
return alg.dot(self.LRGB_TO_LMS, coords, dims=alg.D2_D1)
class Color(Base):
...
Color.register(LMS())
def get_limit(c, channel, upper=False):
if upper:
low = c[channel]
high = 1
else:
high = c[channel]
low = 0
temp = c.clone()
while abs(high - low) >= 0.002:
value = (high + low) * 0.5
temp[channel] = value
if temp.in_gamut('srgb', tolerance=0.01):
if upper:
low = value
else:
high = value
else:
if upper:
high = value
else:
low = value
return temp.clip('srgb')
def confusion_line(c, cvd, method=None):
"""Generate colors on a line of confusion."""
index = ['protan', 'deutan', 'tritan'].index(cvd)
lms = c.convert('lms')
high = get_limit(lms, index, upper=True)
low = get_limit(lms, index)
steps = Color.steps([low, high], steps=100, space='lms', out_space='srgb')
return steps, [s.filter(cvd, method=method).clip() for s in steps]
# pragma: init
normal, cvd = confusion_line(Color('teal'), 'protan')
HtmlSteps(normal)
HtmlSteps(cvd)
normal, cvd = confusion_line(Color('purple'), 'deutan')
HtmlSteps(normal)
HtmlSteps(cvd)
normal, cvd = confusion_line(Color('seagreen'), 'tritan')
HtmlSteps(normal)
HtmlSteps(cvd)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment