Skip to content

Commit dc606ef

Browse files
committed
Update to ColorAide 1.7.1
1 parent 1e451ea commit dc606ef

File tree

13 files changed

+69
-55
lines changed

13 files changed

+69
-55
lines changed

CHANGES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# ColorHelper
22

3+
## 6.1.2
4+
5+
- **FIX**: Update to ColorAide 1.7.1.
6+
37
## 6.1.1
48

59
- **FIX**: Fix broken gamut mapping logic after recent port of latest

lib/coloraide/__meta__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,5 +192,5 @@ def parse_version(ver: str) -> Version:
192192
return Version(major, minor, micro, release, pre, post, dev)
193193

194194

195-
__version_info__ = Version(1, 7, 0, "final")
195+
__version_info__ = Version(1, 7, 1, "final")
196196
__version__ = __version_info__._get_canonical()

lib/coloraide/algebra.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def is_nan(obj: float) -> bool:
7979
return math.isnan(obj)
8080

8181

82-
def no_nans(value: VectorLike, default: float = 0.0) -> Vector:
82+
def no_nans(value: Union[VectorLike, Iterable[float]], default: float = 0.0) -> Vector:
8383
"""Ensure there are no `NaN` values in a sequence."""
8484

8585
return [(default if is_nan(x) else x) for x in value]
@@ -608,7 +608,7 @@ def _extract_dims(
608608
yield m
609609
else:
610610
for m2 in m:
611-
yield from cast(ArrayLike, _extract_dims(cast(ArrayLike, m2), total - 1, target, depth + 1))
611+
yield from _extract_dims(cast(ArrayLike, m2), total - 1, target, depth + 1)
612612

613613

614614
@overload

lib/coloraide/css/serialize.py

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,10 @@
2222
def named_color(obj: 'Color', alpha: Optional[bool], fit: Union[str, bool]) -> Optional[str]:
2323
"""Get the CSS color name."""
2424

25-
a = get_alpha(obj, alpha, False)
25+
a = get_alpha(obj, alpha, False, False)
2626
if a is None:
2727
a = 1
28-
method = None if not isinstance(fit, str) else fit
29-
coords = alg.no_nans(obj.clone().fit(method=method)[:-1])
30-
return to_name(coords + [a])
28+
return to_name(get_coords(obj, fit, False, False) + [a])
3129

3230

3331
def named_color_function(
@@ -44,7 +42,7 @@ def named_color_function(
4442
"""Translate to CSS function form `name(...)`."""
4543

4644
# Create the function `name` or `namea` if old legacy form.
47-
a = get_alpha(obj, alpha, none)
45+
a = get_alpha(obj, alpha, none, legacy)
4846
string = ['{}{}('.format(func, 'a' if legacy and a is not None else EMPTY)]
4947

5048
# Iterate the coordinates formatting them for percent, not percent, and even scaling them (sRGB).
@@ -85,7 +83,7 @@ def color_function(
8583

8684
# Export in the `color(space ...)` format
8785
coords = get_coords(obj, fit, none, False)
88-
a = get_alpha(obj, alpha, none)
86+
a = get_alpha(obj, alpha, none, False)
8987
return (
9088
'color({} {}{})'.format(
9189
obj._space._serialize()[0],
@@ -98,15 +96,14 @@ def color_function(
9896
def get_coords(obj: 'Color', fit: Union[str, bool], none: bool, legacy: bool) -> Vector:
9997
"""Get the coordinates."""
10098

101-
method = None if not isinstance(fit, str) else fit
102-
coords = obj.fit(method=method)[:-1] if fit else obj[:-1]
99+
coords = obj.fit(method=None if not isinstance(fit, str) else fit)[:-1] if fit else obj[:-1]
103100
return alg.no_nans(coords) if legacy or not none else coords
104101

105102

106-
def get_alpha(obj: 'Color', alpha: Optional[bool], none: bool) -> Optional[float]:
103+
def get_alpha(obj: 'Color', alpha: Optional[bool], none: bool, legacy: bool) -> Optional[float]:
107104
"""Get the alpha if required."""
108105

109-
a = alg.no_nan(obj[-1]) if not none else obj[-1]
106+
a = alg.no_nan(obj[-1]) if not none or legacy else obj[-1]
110107
alpha = alpha is not False and (alpha is True or a < 1.0 or alg.is_nan(a))
111108
return None if not alpha else a
112109

@@ -120,9 +117,8 @@ def hexadecimal(
120117
) -> str:
121118
"""Get the hex `RGB` value."""
122119

123-
method = None if not isinstance(fit, str) else fit
124-
coords = [c for c in alg.no_nans(obj.fit(method=method)[:-1])]
125-
a = get_alpha(obj, alpha, False)
120+
coords = get_coords(obj, fit, False, False)
121+
a = get_alpha(obj, alpha, False, False)
126122

127123
if a is not None:
128124
value = "#{:02x}{:02x}{:02x}{:02x}".format(

lib/coloraide/spaces/cam16.py

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import bisect
1111
from ..spaces import Space, Labish
1212
from ..cat import WHITES
13-
from ..channels import Channel
13+
from ..channels import Channel, FLG_MIRROR_PERCENT
1414
from .. import util
1515
from .. import algebra as alg
1616
from ..types import Vector, VectorLike
@@ -85,8 +85,8 @@ def adapt(coords: Vector, fl: float) -> Vector:
8585

8686
adapted = []
8787
for c in coords:
88-
x = math.pow(fl * abs(c) * 0.01, ADAPTED_COEF)
89-
adapted.append(math.copysign(400 * x / (x + 27.13), c))
88+
x = alg.npow(fl * c * 0.01, ADAPTED_COEF)
89+
adapted.append(400 * math.copysign(x, c) / (x + 27.13))
9090
return adapted
9191

9292

@@ -97,7 +97,7 @@ def unadapt(adapted: Vector, fl: float) -> Vector:
9797
constant = 100 / fl * math.pow(27.13, ADAPTED_COEF_INV)
9898
for c in adapted:
9999
cabs = abs(c)
100-
coords.append(math.copysign(constant * math.pow(cabs / (400 - cabs), ADAPTED_COEF_INV), c))
100+
coords.append(math.copysign(constant * alg.npow(cabs / (400 - cabs), ADAPTED_COEF_INV), c))
101101
return coords
102102

103103

@@ -330,18 +330,13 @@ def cam16_jmh_to_xyz_d65(jmh: Vector, env: Environment) -> Vector:
330330
"""CAM16 JMh to XYZ."""
331331

332332
J, M, h = jmh
333-
334-
if alg.is_nan(h): # pragma: no cover
335-
h = 0
336-
337333
return cam16_to_xyz_d65(J=J, M=M, h=h, env=env)
338334

339335

340336
def cam16_jmh_to_cam16_jab(jmh: Vector) -> Vector:
341337
"""Translate a CAM16 JMh to Jab of the same viewing conditions."""
342338

343339
J, M, h = jmh
344-
345340
return [
346341
J,
347342
M * math.cos(math.radians(h)),
@@ -353,6 +348,8 @@ def cam16_jab_to_cam16_jmh(jab: Vector) -> Vector:
353348
"""Translate a CAM16 Jab to JMh of the same viewing conditions."""
354349

355350
J, a, b = jab
351+
if J <= 0.0:
352+
J = a = b = 0.0
356353
M = math.sqrt(a ** 2 + b ** 2)
357354
h = math.degrees(math.atan2(b, a))
358355

@@ -380,9 +377,9 @@ class CAM16(Labish, Space):
380377
NAME = "cam16"
381378
SERIALIZE = ("--cam16",)
382379
CHANNELS = (
383-
Channel("j", 0.0, 100.0),
384-
Channel("a", -90.0, 90.0),
385-
Channel("b", -90.0, 90.0)
380+
Channel("j", 0.0, 100.0, limit=(0.0, None)),
381+
Channel("a", -90.0, 90.0, flags=FLG_MIRROR_PERCENT),
382+
Channel("b", -90.0, 90.0, flags=FLG_MIRROR_PERCENT)
386383
)
387384
CHANNEL_ALIASES = {
388385
"lightness": "j"

lib/coloraide/spaces/cam16_jmh.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from ..channels import Channel, FLG_ANGLE
1616
from .. import algebra as alg
1717
from ..types import Vector
18-
from typing import List, Tuple, Dict
18+
from typing import Dict, List, Tuple
1919

2020

2121
class Achromatic:
@@ -101,6 +101,24 @@ def scale(self, point: float) -> float:
101101
point = size * index + (adjusted * size)
102102
return point
103103

104+
def get_ideal_chroma(self, j: float, m: float) -> float:
105+
"""Get the ideal chroma."""
106+
107+
if j < 0.0: # pragma: no cover
108+
return 0.0
109+
110+
if self.spline is not None:
111+
point = self.scale(j)
112+
m2 = self.spline(point)[1]
113+
if abs(m2 - m) < self.threshold:
114+
return m
115+
elif m < m2:
116+
return m2
117+
118+
# This would be for `discounting=True`,
119+
# which we do not run with currently.
120+
return m # pragma: no cover
121+
104122
def test(self, j: float, m: float) -> bool:
105123
"""Test if the current color is achromatic."""
106124

@@ -130,8 +148,8 @@ class CAM16JMh(LChish, Space):
130148
NAME = "cam16-jmh"
131149
SERIALIZE = ("--cam16-jmh",)
132150
CHANNELS = (
133-
Channel("j", 0.0, 100.0),
134-
Channel("m", 0, 55.0, limit=(0.0, None)),
151+
Channel("j", 0.0, 100.0, limit=(0.0, None)),
152+
Channel("m", 0, 105.0, limit=(0.0, None)),
135153
Channel("h", 0.0, 360.0, flags=FLG_ANGLE)
136154
)
137155
CHANNEL_ALIASES = {
@@ -176,6 +194,7 @@ def to_base(self, coords: Vector) -> Vector:
176194

177195
j, m = coords[:2]
178196
if self.ACHROMATIC.test(j, m):
197+
coords[1] = self.ACHROMATIC.get_ideal_chroma(j, m)
179198
coords[2] = self.ACHROMATIC.hue
180199

181200
return cam16_jmh_to_cam16_jab(coords)

lib/coloraide/spaces/cam16_ucs.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import math
99
from . cam16 import CAM16
1010
from ..types import Vector
11-
from ..channels import Channel
11+
from ..channels import Channel, FLG_MIRROR_PERCENT
1212

1313
COEFFICENTS = {
1414
'lcd': (0.77, 0.007, 0.0053),
@@ -79,9 +79,9 @@ class CAM16UCS(CAM16):
7979
SERIALIZE = ("--cam16-ucs",)
8080
MODEL = 'ucs'
8181
CHANNELS = (
82-
Channel("j", 0.0, 100.0),
83-
Channel("a", -50.0, 50.0),
84-
Channel("b", -50.0, 50.0)
82+
Channel("j", 0.0, 100.0, limit=(0.0, None)),
83+
Channel("a", -50.0, 50.0, flags=FLG_MIRROR_PERCENT),
84+
Channel("b", -50.0, 50.0, flags=FLG_MIRROR_PERCENT)
8585
)
8686

8787
def to_base(self, coords: Vector) -> Vector:
@@ -103,9 +103,9 @@ class CAM16LCD(CAM16UCS):
103103
ENV = ENV = CAM16.ENV
104104
MODEL = 'lcd'
105105
CHANNELS = (
106-
Channel("j", 0.0, 100.0),
107-
Channel("a", -70.0, 70.0),
108-
Channel("b", -70.0, 70.0)
106+
Channel("j", 0.0, 100.0, limit=(0.0, None)),
107+
Channel("a", -70.0, 70.0, flags=FLG_MIRROR_PERCENT),
108+
Channel("b", -70.0, 70.0, flags=FLG_MIRROR_PERCENT)
109109
)
110110

111111

@@ -117,7 +117,7 @@ class CAM16SCD(CAM16UCS):
117117
ENV = ENV = CAM16.ENV
118118
MODEL = 'scd'
119119
CHANNELS = (
120-
Channel("j", 0.0, 100.0),
121-
Channel("a", -40.0, 40.0),
122-
Channel("b", -40.0, 40.0)
120+
Channel("j", 0.0, 100.0, limit=(0.0, None)),
121+
Channel("a", -40.0, 40.0, flags=FLG_MIRROR_PERCENT),
122+
Channel("b", -40.0, 40.0, flags=FLG_MIRROR_PERCENT)
123123
)

lib/coloraide/spaces/din99o.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ def lab_to_din99o(lab: Vector) -> Vector:
3838
"""XYZ to DIN99o."""
3939

4040
l, a, b = lab
41-
val = 1 + C2 * l
42-
l99o = C1 * math.copysign(math.log(abs(val)), val) / KE
41+
val = 1 + abs(C2 * l)
42+
l99o = C1 * math.copysign(1, l) * math.log(val) / KE
4343

4444
if a == 0 and b == 0:
4545
a99o = b99o = 0.0
@@ -48,7 +48,7 @@ def lab_to_din99o(lab: Vector) -> Vector:
4848
fo = FACTOR * (b * math.cos(RADS) - a * math.sin(RADS))
4949
go = math.sqrt(eo ** 2 + fo ** 2)
5050
val = 1 + C3 * go
51-
c99o = math.copysign(math.log(abs(val)), val) / (C4 * KE * KCH)
51+
c99o = math.log(val) / (C4 * KE * KCH)
5252
h99o = math.atan2(fo, eo) + RADS
5353

5454
a99o = c99o * math.cos(h99o)
@@ -76,15 +76,12 @@ def din99o_to_lab(din99o: Vector) -> Vector:
7676

7777
l99o, c99o, h99o = din99o_lab_to_lch(din99o)
7878
val = C4 * c99o * KCH * KE
79-
g = (math.copysign(math.exp(abs(val)), val) - 1) / C3
79+
g = (math.exp(val) - 1) / C3
8080
e = g * math.cos(h99o - RADS)
8181
f = g * math.sin(h99o - RADS)
8282

83-
val = (l99o * KE) / C1
84-
(math.copysign(math.exp(abs(val)), val) - 1) / C2
85-
8683
return [
87-
(math.exp((l99o * KE) / C1) - 1) / C2,
84+
math.copysign(1, l99o) * (math.exp((abs(l99o) * KE) / C1) - 1) / C2,
8885
e * math.cos(RADS) - (f / FACTOR) * math.sin(RADS),
8986
e * math.sin(RADS) + (f / FACTOR) * math.cos(RADS)
9087
]

lib/coloraide/spaces/hct.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ def to_base(self, coords: Vector) -> Vector:
219219

220220
m, j = coords[1:3]
221221
if self.ACHROMATIC.test(j, m):
222+
coords[1] = self.ACHROMATIC.get_ideal_chroma(j, m)
222223
coords[0] = self.ACHROMATIC.hue
223224

224225
return hct_to_xyz(coords, self.ENV)

lib/coloraide/spaces/ipt.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,9 @@ class IPT(Labish, Space):
7474
NAME = "ipt"
7575
SERIALIZE = ("--ipt",) # type: Tuple[str, ...]
7676
CHANNELS = (
77-
Channel("i", 0.0, 1.0, bound=True),
78-
Channel("p", -1.0, 1.0, bound=True, flags=FLG_MIRROR_PERCENT),
79-
Channel("t", -1.0, 1.0, bound=True, flags=FLG_MIRROR_PERCENT)
77+
Channel("i", 0.0, 1.0),
78+
Channel("p", -1.0, 1.0, flags=FLG_MIRROR_PERCENT),
79+
Channel("t", -1.0, 1.0, flags=FLG_MIRROR_PERCENT)
8080
)
8181
CHANNEL_ALIASES = {
8282
"intensity": "i",

0 commit comments

Comments
 (0)