Last active
August 23, 2026 20:13
-
-
Save facelessuser/03fa7645c98d005fe4bad95a78300bd6 to your computer and use it in GitHub Desktop.
DLM
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """ | |
| DLM color space. | |
| This is a prototype of the space as described here: https://prototypestudios.neocities.org/dlm | |
| We have not bothered to see exactly how they do their space, but have instead just implemented it as described. | |
| Any errors in implementation are likely our own. | |
| """ | |
| from __future__ import annotations | |
| import math | |
| from coloraide.spaces import Space, Prism, Luminant | |
| from coloraide.channels import Channel | |
| from coloraide.cat import WHITES | |
| from coloraide import util | |
| from coloraide.types import Vector | |
| from coloraide import algebra as alg | |
| from coloraide.spectrum import closest_wavelength, wavelength_to_color | |
| from coloraide.everything import ColorAll as Base | |
| # Fixed primary | |
| FP = util.xyz_to_xyY(wavelength_to_color(650))[:-1] | |
| class DLM(Luminant, Prism, Space): | |
| """The xyY class.""" | |
| BASE = "xyy" | |
| NAME = "dlm" | |
| SERIALIZE = ("--dlm",) | |
| CHANNELS = ( | |
| Channel("d", 360, 830), | |
| Channel("l", 0.0, 1.0), | |
| Channel("m", 0.0, 1.0) | |
| ) | |
| WHITE = WHITES['2deg']['D65'] | |
| def to_base(self, coords: Vector) -> Vector: | |
| """To XYZ.""" | |
| d, l, m = coords | |
| dx, dy = util.xyz_to_xyY(wavelength_to_color(alg.clamp(d, 360, 830)))[:-1] | |
| fx, fy = FP | |
| x = alg.lerp(fx, dx, m) | |
| y = alg.lerp(fy, dy, m) | |
| return [x, y, l] | |
| def from_base(self, coords: Vector) -> Vector: | |
| """From XYZ.""" | |
| x, y, Y = coords | |
| # We don't want the rounded wavelength, so don't get the "closest", | |
| # but get the raw, interpolated value. | |
| w = closest_wavelength([x, y], FP, closest=False) | |
| xf, yf = FP | |
| xd, yd = w[1] | |
| d = w[0] | |
| # On the line of purples, use 440 instead | |
| if d < 0 or math.isnan(d): | |
| d = 440 | |
| xd, yd = util.xyz_to_xyY(wavelength_to_color(d))[:-1] | |
| # We could clamp this to a smaller subset, but I don't think it matters. | |
| d = alg.clamp(d, 360, 830) | |
| # Calculate the mix | |
| dx = xd - xf | |
| dy = yd - yf | |
| m = alg.zdiv(x - xf, dx) if dx - dy else alg.zdiv(y - yf, dy) | |
| # If mix exceeds the range, return the dominant wavelength | |
| if m < 0 or m > 1: | |
| d = closest_wavelength([x, y], closest=False)[0] | |
| m = 1 | |
| return [d, Y, m] | |
| def lightness_name(self) -> str: | |
| """Get lightness name.""" | |
| return "l" | |
| class Color(Base): ... | |
| Color.register(DLM()) | |
| Color.interpolate(['#002185', '#FCD200'], space='dlm') | |
| Color.interpolate(['black', 'white'], space='dlm') | |
| Color.interpolate([Color('dlm', [650, 0.5, 1]), Color('dlm', [520, 0.5, 1])], space='dlm') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment