Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions coloraide/average.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Average colors together."""
from __future__ import annotations
import math
from . import util
from .spaces import HWBish
from .types import ColorInput
from typing import Iterable, TYPE_CHECKING
Expand All @@ -9,9 +10,6 @@
from .color import Color


ACHROMATIC_THRESHOLD = 1e-4


def average(
color_cls: type[Color],
colors: Iterable[ColorInput],
Expand Down Expand Up @@ -88,7 +86,7 @@ def average(
else:
sin /= total
cos /= total
if abs(sin) < ACHROMATIC_THRESHOLD and abs(cos) < ACHROMATIC_THRESHOLD:
if abs(sin) < util.ACHROMATIC_THRESHOLD_SM and abs(cos) < util.ACHROMATIC_THRESHOLD_SM:
sums[i] = math.nan
else:
avg_theta = math.degrees(math.atan2(sin, cos))
Expand Down
7 changes: 3 additions & 4 deletions coloraide/spaces/cam16_jmh.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@
import bisect
from .. import util
from .. import algebra as alg
from ..spaces import Space, LChish
from .lch import LCh
from ..cat import WHITES, CAT16
from ..channels import Channel, FLG_ANGLE
from .lch import ACHROMATIC_THRESHOLD
from ..types import Vector, VectorLike

# CAT16
Expand Down Expand Up @@ -352,7 +351,7 @@ def cam_jmh_to_xyz(jmh: Vector, env: Environment) -> Vector:
return cam_to_xyz(J=J, M=M, h=h, env=env)


class CAM16JMh(LChish, Space):
class CAM16JMh(LCh):
"""CAM16 class (JMh)."""

BASE = "xyz-d65"
Expand Down Expand Up @@ -396,7 +395,7 @@ def is_achromatic(self, coords: Vector) -> bool | None:
"""Check if color is achromatic."""

# Account for both positive and negative chroma
return coords[0] == 0 or abs(coords[1]) < ACHROMATIC_THRESHOLD
return coords[0] == 0 or abs(coords[1]) < self.achromatic_threshold

def to_base(self, coords: Vector) -> Vector:
"""From CAM16 JMh to XYZ."""
Expand Down
7 changes: 3 additions & 4 deletions coloraide/spaces/cam16_ucs.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
from __future__ import annotations
import math
from .cam16_jmh import CAM16JMh, xyz_to_cam, cam_to_xyz, Environment
from ..spaces import Space, Labish
from .lch import ACHROMATIC_THRESHOLD
from .lab import Lab
from ..cat import WHITES
from .. import util
from ..channels import Channel, FLG_MIRROR_PERCENT
Expand Down Expand Up @@ -91,7 +90,7 @@ def cam_ucs_to_cam_jmh(ucs: Vector, model: str) -> Vector:
]


class CAM16UCS(Labish, Space):
class CAM16UCS(Lab):
"""CAM16 UCS (Jab) class."""

BASE = "cam16-jmh"
Expand All @@ -114,7 +113,7 @@ def is_achromatic(self, coords: Vector) -> bool:
"""Check if color is achromatic."""

j, m = cam_ucs_to_cam_jmh(coords, self.MODEL)[:-1]
return j == 0 or abs(m) < ACHROMATIC_THRESHOLD
return j == 0 or abs(m) < self.achromatic_threshold

def to_base(self, coords: Vector) -> Vector:
"""To CAM16 JMh from CAM16."""
Expand Down
3 changes: 2 additions & 1 deletion coloraide/spaces/cmy.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Uncalibrated, naive CMY color space."""
from __future__ import annotations
from .. import util
from ..spaces import Regular, Space
from ..channels import Channel
from ..cat import WHITES
Expand Down Expand Up @@ -43,7 +44,7 @@ def is_achromatic(self, coords: Vector) -> bool:

black = [1, 1, 1]
for x in alg.vcross(coords, black):
if not math.isclose(0.0, x, abs_tol=1e-4):
if not math.isclose(0.0, x, abs_tol=util.ACHROMATIC_THRESHOLD_SM):
return False
return True

Expand Down
5 changes: 3 additions & 2 deletions coloraide/spaces/cmyk.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
https://www.w3.org/TR/css-color-5/#cmyk-rgb
"""
from __future__ import annotations
from .. import util
from ..spaces import Space
from ..channels import Channel
from ..cat import WHITES
Expand Down Expand Up @@ -60,12 +61,12 @@ class CMYK(Space):
def is_achromatic(self, coords: Vector) -> bool:
"""Test if color is achromatic."""

if math.isclose(1.0, coords[-1], abs_tol=1e-4):
if math.isclose(1.0, coords[-1], abs_tol=util.ACHROMATIC_THRESHOLD_SM):
return True

black = [1, 1, 1]
for x in alg.vcross(coords[:-1], black):
if not math.isclose(0.0, x, abs_tol=1e-5):
if not math.isclose(0.0, x, abs_tol=util.ACHROMATIC_THRESHOLD_SM):
return False
return True

Expand Down
6 changes: 3 additions & 3 deletions coloraide/spaces/cubehelix.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
THIS SOFTWARE.
"""
from __future__ import annotations
from ..spaces import Space, HSLish
from . hsl import HSL
from ..cat import WHITES
from ..channels import Channel, FLG_ANGLE
import math
Expand Down Expand Up @@ -72,7 +72,7 @@ def cubehelix_to_srgb(coords: Vector) -> Vector:
]


class Cubehelix(HSLish, Space):
class Cubehelix(HSL):
"""Cubehelix class."""

BASE = 'srgb'
Expand Down Expand Up @@ -103,7 +103,7 @@ def normalize(self, coords: Vector) -> Vector:
def is_achromatic(self, coords: Vector) -> bool:
"""Check if color is achromatic."""

return abs(coords[1]) < 1e-4 or coords[2] > (1 - 1e-7) or coords[2] < 1e-08
return abs(coords[1]) < self.achromatic_threshold or coords[2] > (1 - 1e-7) or coords[2] < 1e-08

def to_base(self, coords: Vector) -> Vector:
"""To LChuv from HSLuv."""
Expand Down
7 changes: 3 additions & 4 deletions coloraide/spaces/hct.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,11 @@
"""
from __future__ import annotations
from .. import algebra as alg
from ..spaces import Space, LChish
from .lch import LCh
from ..cat import WHITES
from ..channels import Channel, FLG_ANGLE
from .cam16_jmh import Environment, cam_to_xyz, xyz_to_cam
from .lab import EPSILON, KAPPA, KE
from .lch import ACHROMATIC_THRESHOLD
from ..types import Vector
import math

Expand Down Expand Up @@ -156,7 +155,7 @@ def xyz_to_hct(coords: Vector, env: Environment) -> Vector:
return [h, c, t]


class HCT(LChish, Space):
class HCT(LCh):
"""HCT class."""

BASE = "xyz-d65"
Expand Down Expand Up @@ -200,7 +199,7 @@ def is_achromatic(self, coords: Vector) -> bool | None:
"""Check if color is achromatic."""

# Account for both positive and negative chroma
return coords[2] == 0 or abs(coords[1]) < ACHROMATIC_THRESHOLD
return coords[2] == 0 or abs(coords[1]) < self.achromatic_threshold

def names(self) -> tuple[Channel, ...]:
"""Return LCh-ish names in the order L C h."""
Expand Down
7 changes: 4 additions & 3 deletions coloraide/spaces/hpluv.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
SOFTWARE.
"""
from __future__ import annotations
from ..spaces import Space, HSLish
from .hsl import HSL
from ..cat import WHITES
from ..channels import Channel, FLG_ANGLE
from .lab import EPSILON, KAPPA
Expand Down Expand Up @@ -103,7 +103,7 @@ def luv_to_hpluv(luv: Vector) -> Vector:
return [util.constrain_hue(h), s, l]


class HPLuv(HSLish, Space):
class HPLuv(HSL):
"""HPLuv class."""

BASE = 'luv'
Expand All @@ -120,6 +120,7 @@ class HPLuv(HSLish, Space):
"lightness": "l"
}
WHITE = WHITES['2deg']['D65']
GAMUT_CHECK = None

def normalize(self, coords: Vector) -> Vector:
"""Normalize coordinates."""
Expand All @@ -132,7 +133,7 @@ def normalize(self, coords: Vector) -> Vector:
def is_achromatic(self, coords: Vector) -> bool:
"""Check if color is achromatic."""

return abs(coords[1]) < 1e-4 or coords[2] > (100 - 1e-7) or coords[2] < 1e-08
return abs(coords[1]) < self.achromatic_threshold or coords[2] > (100 - 1e-7) or coords[2] < 1e-08

def to_base(self, coords: Vector) -> Vector:
"""To LChuv from HPLuv."""
Expand Down
15 changes: 14 additions & 1 deletion coloraide/spaces/hsl/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
"""HSL class."""
from __future__ import annotations
from ... import algebra as alg
from ...spaces import HSLish, Space
from ...cat import WHITES
from ...channels import Channel, FLG_ANGLE
from ... import util
from ...types import Vector
from typing import Any


def srgb_to_hsl(rgb: Vector) -> Vector:
Expand Down Expand Up @@ -82,6 +84,13 @@ class HSL(HSLish, Space):
GAMUT_CHECK = "srgb" # type: str | None
CLIP_SPACE = "hsl" # type: str | None

def __init__(self, **kwargs: Any):
"""Initialize."""

super().__init__(**kwargs)
order = alg.order(self.channels[self.indexes()[2]].high)
self.achromatic_threshold = util.ACHROMATIC_THRESHOLD_SM if order == 0 else util.ACHROMATIC_THRESHOLD

def normalize(self, coords: Vector) -> Vector:
"""Normalize coordinates."""

Expand All @@ -94,7 +103,11 @@ def normalize(self, coords: Vector) -> Vector:
def is_achromatic(self, coords: Vector) -> bool | None:
"""Check if color is achromatic."""

return abs(coords[1]) < 1e-4 or coords[2] == 0.0 or abs(1 - coords[2]) < 1e-7
return (
abs(coords[1]) < self.achromatic_threshold or
coords[2] == 0.0 or
abs(1 - coords[2]) < self.achromatic_threshold
)

def to_base(self, coords: Vector) -> Vector:
"""To sRGB from HSL."""
Expand Down
6 changes: 3 additions & 3 deletions coloraide/spaces/hsluv.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@
SOFTWARE.
"""
from __future__ import annotations
from ..spaces import Space, HSLish
from ..cat import WHITES
from ..channels import Channel, FLG_ANGLE
from .hsl import HSL
from .lab import EPSILON, KAPPA
from .srgb_linear import XYZ_TO_RGB
import math
Expand Down Expand Up @@ -106,7 +106,7 @@ def luv_to_hsluv(luv: Vector) -> Vector:
return [util.constrain_hue(h), s, l]


class HSLuv(HSLish, Space):
class HSLuv(HSL):
"""HSLuv class."""

BASE = 'luv'
Expand Down Expand Up @@ -137,7 +137,7 @@ def normalize(self, coords: Vector) -> Vector:
def is_achromatic(self, coords: Vector) -> bool:
"""Check if color is achromatic."""

return abs(coords[1]) < 1e-4 or coords[2] > (100 - 1e-7) or coords[2] < 1e-08
return abs(coords[1]) < self.achromatic_threshold or coords[2] > (100 - 1e-7) or coords[2] < 1e-08

def to_base(self, coords: Vector) -> Vector:
"""To LChuv from HSLuv."""
Expand Down
11 changes: 10 additions & 1 deletion coloraide/spaces/hsv.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
"""HSV class."""
from __future__ import annotations
from .. import algebra as alg
from ..spaces import Space, HSVish
from ..cat import WHITES
from ..channels import Channel, FLG_ANGLE
from .. import util
from ..types import Vector
from typing import Any


def hsv_to_srgb(hsv: Vector) -> Vector:
Expand Down Expand Up @@ -77,6 +79,13 @@ class HSV(HSVish, Space):
CLIP_SPACE = "hsv" # type: str | None
WHITE = WHITES['2deg']['D65']

def __init__(self, **kwargs: Any):
"""Initialize."""

super().__init__(**kwargs)
order = alg.order(self.channels[self.indexes()[2]].high)
self.achromatic_threshold = util.ACHROMATIC_THRESHOLD_SM if order == 0 else util.ACHROMATIC_THRESHOLD

def normalize(self, coords: Vector) -> Vector:
"""Normalize coordinates."""

Expand All @@ -88,7 +97,7 @@ def normalize(self, coords: Vector) -> Vector:
def is_achromatic(self, coords: Vector) -> bool:
"""Check if color is achromatic."""

return abs(coords[1]) < 1e-5 or coords[2] == 0.0
return abs(coords[1]) < self.achromatic_threshold or coords[2] == 0.0

def to_base(self, coords: Vector) -> Vector:
"""To HSL from HSV."""
Expand Down
3 changes: 1 addition & 2 deletions coloraide/spaces/jzazbz.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
If at some time that these assumptions are incorrect, we will be happy to alter the model.
"""
from __future__ import annotations
from ..spaces import Space
from ..cat import WHITES
from ..channels import Channel, FLG_MIRROR_PERCENT
from .. import util
Expand Down Expand Up @@ -122,7 +121,7 @@ def xyz_to_jzazbz(xyz: Vector) -> Vector:
return [jz, az, bz]


class Jzazbz(Lab, Space):
class Jzazbz(Lab):
"""Jzazbz class."""

BASE = "xyz-d65"
Expand Down
12 changes: 10 additions & 2 deletions coloraide/spaces/lab/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@
from ...cat import WHITES
from ...channels import Channel, FLG_MIRROR_PERCENT
from ... import util
from ... util import ACHROMATIC_THRESHOLD
from ... import algebra as alg
from ...types import VectorLike, Vector
from typing import Any

ACHROMATIC_THRESHOLD = 1e-4
EPSILON = 216 / 24389 # `6^3 / 29^3`
EPSILON3 = 6 / 29 # Cube root of EPSILON
KAPPA = 24389 / 27
Expand Down Expand Up @@ -67,10 +68,17 @@ class Lab(Labish, Space):
"lightness": "l"
}

def __init__(self, **kwargs: Any):
"""Initialize."""

super().__init__(**kwargs)
order = alg.order(self.channels[self.indexes()[0]].high)
self.achromatic_threshold = util.ACHROMATIC_THRESHOLD_SM if order == 0 else ACHROMATIC_THRESHOLD

def is_achromatic(self, coords: Vector) -> bool:
"""Check if color is achromatic."""

return alg.rect_to_polar(coords[1], coords[2])[0] < ACHROMATIC_THRESHOLD
return alg.rect_to_polar(coords[1], coords[2])[0] < self.achromatic_threshold

def to_base(self, coords: Vector) -> Vector:
"""To XYZ D50 from Lab."""
Expand Down
Loading