Skip to content

Instantly share code, notes, and snippets.

@facelessuser
Last active April 14, 2023 16:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save facelessuser/c769cecafc8071de6f73da7dcd45f7ba to your computer and use it in GitHub Desktop.
Save facelessuser/c769cecafc8071de6f73da7dcd45f7ba to your computer and use it in GitHub Desktop.
XYB Notes
"""XYB color space."""
from __future__ import annotations
from coloraide import algebra as alg
from coloraide.spaces import Space
from coloraide.types import Vector
from coloraide.cat import WHITES
from coloraide.channels import Channel, FLG_MIRROR_PERCENT
from coloraide import Color as Base

BIAS = 0.00379307325527544933
BIAS_CBRT = alg.nth_root(BIAS, 3)
LRGB_TO_LMS = [
    [0.3, 0.622, 0.078],
    [0.23, 0.692, 0.078],
    [0.24342268924547819, 0.20476744424496821, 0.55180986650955360]
]

LMS_TO_LRGB = alg.inv(LRGB_TO_LMS)


def rgb_to_xyb(rgb: Vector) -> Vector:
    """Linear sRGB to XYB."""

    lgamma, mgamma, sgamma = [alg.nth_root(c + BIAS, 3) - BIAS_CBRT for c in alg.dot(LRGB_TO_LMS, rgb)]
    return [
        (lgamma - mgamma) / 2,
        (lgamma + mgamma) / 2,
        sgamma
    ]


def xyb_to_rgb(xyb: Vector) -> Vector:
    """XYB to linear sRGB."""

    x, y, sgamma = xyb
    x *= 2
    y *= 2
    lgamma = (x + y) / 2
    mgamma = y - lgamma

    return alg.dot(LMS_TO_LRGB, [(c + BIAS_CBRT) ** 3  - BIAS for c in [lgamma, mgamma, sgamma]])


class XYB(Space):
    """XYB color class."""

    BASE = 'srgb-linear'
    NAME = "xyb"
    SERIALIZE = ("--xyb",)
    WHITE = WHITES['2deg']['D65']
    # Range in Display-P3
    CHANNELS = (
        Channel("x", -0.02, 0.033),
        Channel("y", 0.0, 0.845, flags=FLG_MIRROR_PERCENT),
        Channel("b", 0.0, 0.845, flags=FLG_MIRROR_PERCENT)
    )

    def to_base(self, coords: Vector) -> Vector:
        """To XYB from base."""

        return xyb_to_rgb(coords)

    def from_base(self, coords: Vector) -> Vector:
        """From base to XYB."""

        return rgb_to_xyb(coords)

class Color(Base): ...

Color.register(XYB())

Color('red').convert('xyb')
Color('white').convert('xyb')
Color('purple').convert('xyb')
<iframe height="300" style="width: 100%;" scrolling="no" title="XYB Example" src="https://codepen.io/facelessuser/embed/LYgNVvY?default-tab=html%2Cresult" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true"> See the Pen XYB Example by Isaac Muse (@facelessuser) on CodePen. </iframe>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment