Skip to content

Commit 623fdeb

Browse files
authored
Upgrade to use coloraide 2.0.x (#247)
1 parent dc606ef commit 623fdeb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+2620
-1827
lines changed

ch_tool_contrast.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ def evaluate(base, string):
121121
colors.append(second.fit('srgb'))
122122
if ratio:
123123
if first[-1] < 1.0:
124-
first = first.compose(second, space="srgb")
124+
first = first.compose(second, space="srgb", out_space=first.space())
125125
hwb_fg = first.convert('hwb').clip()
126126
hwb_bg = second.convert('hwb').clip()
127127
first.update(hwb_fg)
@@ -140,10 +140,10 @@ def evaluate(base, string):
140140

141141
if first[-1] < 1.0:
142142
# Contrasted with current color
143-
colors.append(first.compose(second, space="srgb"))
143+
colors.append(first.compose(second, space="srgb", out_space=first.space()))
144144
# Contrasted with the two extremes min and max
145-
colors.append(first.compose("white", space="srgb"))
146-
colors.append(first.compose("black", space="srgb"))
145+
colors.append(first.compose("white", space="srgb", out_space=first.space()))
146+
colors.append(first.compose("black", space="srgb", out_space=first.space()))
147147
else:
148148
colors.append(first)
149149
except Exception as e:

ch_util.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,38 @@
1111
import base64
1212
import importlib
1313
from .lib.coloraide import Color as Base
14-
from .lib.coloraide.css.parse import RE_COLOR_MATCH
1514
from .lib.coloraide import __version_info__ as coloraide_version
1615
import functools
16+
import re
17+
18+
COLOR_PARTS = {
19+
"strict_percent": r"(?:[+\-]?(?:[0-9]*\.)?[0-9]+(?:e[-+]?[0-9]+)?%)",
20+
"strict_float": r"(?:[+\-]?(?:[0-9]*\.)?[0-9]+(?:e[-+]?[0-9]+)?)",
21+
"strict_angle": r"(?:[+\-]?(?:[0-9]*\.)?[0-9]+(?:e[-+]?[0-9]+)?(?:deg|rad|turn|grad)?)",
22+
"percent": r"(?:[+\-]?(?:[0-9]*\.)?[0-9]+(?:e[-+]?[0-9]+)?%|none)",
23+
"float": r"(?:[+\-]?(?:[0-9]*\.)?[0-9]+(?:e[-+]?[0-9]+)?|none)",
24+
"angle": r"(?:[+\-]?(?:[0-9]*\.)?[0-9]+(?:e[-+]?[0-9]+)?(?:deg|rad|turn|grad)?|none)",
25+
"space": r"\s+",
26+
"loose_space": r"\s*",
27+
"comma": r"\s*,\s*",
28+
"slash": r"\s*/\s*",
29+
"sep": r"(?:\s*,\s*|\s+)",
30+
"asep": r"(?:\s*[,/]\s*|\s+)",
31+
"hex": r"[a-f0-9]"
32+
}
33+
34+
35+
# Allow 15 channels maximum. This should be able to handle any colors we throw at it.
36+
RE_COLOR_MATCH = re.compile(
37+
r"""(?xi)
38+
color\(\s*
39+
(-{{0,2}}[a-z][-a-z0-9_]*)(?=\s)
40+
((?:{loose_space}(?:{strict_percent}|{float})){{1,15}}(?:{slash}(?:{strict_percent}|{float}))?)
41+
\s*\)
42+
""".format(
43+
**COLOR_PARTS
44+
)
45+
)
1746

1847
SUPPORTED_SPACES = list(Base.CS_MAP.values())
1948

color_helper.sublime-settings

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,15 @@
122122
// "ColorHelper.lib.coloraide.spaces.acescc.ACEScc",
123123
// "ColorHelper.lib.coloraide.spaces.acescg.ACEScg",
124124
// "ColorHelper.lib.coloraide.spaces.acescct.ACEScct",
125+
// "ColorHelper.lib.coloraide.spaces.cam16.CAM16",
126+
// "ColorHelper.lib.coloraide.spaces.cam16_jmh.CAM16JMh",
127+
// "ColorHelper.lib.coloraide.spaces.cam16_ucs.CAM16UCS",
128+
// "ColorHelper.lib.coloraide.spaces.cam16_ucs.CAM16SCD",
129+
// "ColorHelper.lib.coloraide.spaces.cam16_ucs.CAM16LCD",
125130
// "ColorHelper.lib.coloraide.spaces.cmy.CMY",
126131
// "ColorHelper.lib.coloraide.spaces.cmyk.CMYK",
127132
// "ColorHelper.lib.coloraide.spaces.din99o.DIN99o",
133+
// "ColorHelper.lib.coloraide.spaces.hct.HCT",
128134
// "ColorHelper.lib.coloraide.spaces.hpluv.HPLuv",
129135
// "ColorHelper.lib.coloraide.spaces.hsi.HSI",
130136
// "ColorHelper.lib.coloraide.spaces.hunter_lab.HunterLab",
@@ -136,10 +142,9 @@
136142
// "ColorHelper.lib.coloraide.spaces.lch99o.LCh99o",
137143
// "ColorHelper.lib.coloraide.spaces.orgb.oRGB",
138144
// "ColorHelper.lib.coloraide.spaces.prismatic.Prismatic",
139-
// "ColorHelper.lib.coloraide.spaces.rec2100pq.Rec2100PQ",
145+
// "ColorHelper.lib.coloraide.spaces.rec2100_hlg.Rec2100HLG",
146+
// "ColorHelper.lib.coloraide.spaces.rec2100_pq.Rec2100PQ",
140147
// "ColorHelper.lib.coloraide.spaces.rlab.RLAB",
141-
// "ColorHelper.lib.coloraide.spaces.ucs.UCS",
142-
// "ColorHelper.lib.coloraide.spaces.uvw.UVW",
143148
// "ColorHelper.lib.coloraide.spaces.xyy.xyY",
144149
"ColorHelper.lib.coloraide.spaces.hsluv.HSLuv",
145150
"ColorHelper.lib.coloraide.spaces.lchuv.LChuv",

custom/ahex.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def to_string(
5252
"""Convert to Hex format."""
5353

5454
options = kwargs
55-
a = alg.no_nan(parent[-1])
55+
a = parent.alpha(nans=False)
5656
show_alpha = alpha is not False and (alpha is True or a < 1.0)
5757

5858
template = "#{:02x}{:02x}{:02x}{:02x}" if show_alpha else "#{:02x}{:02x}{:02x}"
@@ -61,7 +61,7 @@ def to_string(
6161

6262
# Always fit hex
6363
method = None if not isinstance(fit, str) else fit
64-
coords = alg.no_nans(parent.clone().fit(method=method)[:-1])
64+
coords = parent.clone().fit(method=method).coords(nans=False)
6565
if show_alpha:
6666
value = template.format(
6767
int(alg.round_half_up(a * 255.0)),

custom/ass_abgr.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def to_string(cls, parent, *, options=None, alpha=None, precision=None, fit=True
4646
"""Convert color to `&HAABBGGRR`."""
4747

4848
options = kwargs
49-
a = alg.no_nan(parent[-1])
49+
a = parent.alpha(nans=False)
5050
show_alpha = alpha is not False and (alpha is True or a < 1.0)
5151

5252
template = "&H{:02x}{:02x}{:02x}{:02x}" if show_alpha else "&H{:02x}{:02x}{:02x}"
@@ -55,7 +55,7 @@ def to_string(cls, parent, *, options=None, alpha=None, precision=None, fit=True
5555

5656
# Always fit hex
5757
method = None if not isinstance(fit, str) else fit
58-
coords = alg.no_nans(parent.clone().fit(method=method)[:-1])
58+
coords = parent.clone().fit(method=method).coords(nans=False)
5959
if show_alpha:
6060
value = template.format(
6161
int(alg.round_half_up(a * 255.0)),

custom/st_colormod.py

Lines changed: 39 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
from itertools import zip_longest as zipl
1010
import functools
1111
import math
12-
from ColorHelper.ch_util import get_base_color
12+
from ColorHelper.ch_util import get_base_color, COLOR_PARTS
13+
14+
RE_CHAN_VALUE = re.compile(r'(?i)(?:[+\-]?(?:[0-9]*\.)?[0-9]+(?:e[-+]?[0-9]+)?(?:%|deg|rad|turn|grad)?|none)')
1315

1416
BASE = get_base_color()
1517

@@ -27,10 +29,10 @@
2729
\#(?:{hex}{{6}}(?:{hex}{{2}})?|{hex}{{3}}(?:{hex})?) |
2830
[\w][\w\d]*
2931
)
30-
""".format(**parse.COLOR_PARTS)
32+
""".format(**COLOR_PARTS)
3133
),
3234
"functions": re.compile(r'(?i)[\w][\w\d]*\('),
33-
"separators": re.compile(r'(?:{comma}|{space}|{slash})'.format(**parse.COLOR_PARTS))
35+
"separators": re.compile(r'(?:{comma}|{space}|{slash})'.format(**COLOR_PARTS))
3436
}
3537

3638
RE_ADJUSTERS = {
@@ -41,38 +43,38 @@
4143
(?:(\+\s+|\-\s+)?({strict_percent}|{strict_float})|(\*)?\s*({strict_percent}|{strict_float}))
4244
\s*\)
4345
""".format(
44-
**parse.COLOR_PARTS
46+
**COLOR_PARTS
4547
)
4648
),
4749
"saturation": re.compile(
48-
r'(?i)\s+s(?:aturation)?\((\+\s|\-\s|\*)?\s*({strict_percent})\s*\)'.format(**parse.COLOR_PARTS)
50+
r'(?i)\s+s(?:aturation)?\((\+\s|\-\s|\*)?\s*({strict_percent})\s*\)'.format(**COLOR_PARTS)
4951
),
5052
"lightness": re.compile(
51-
r'(?i)\s+l(?:ightness)?\((\+\s|\-\s|\*)?\s*({strict_percent})\s*\)'.format(**parse.COLOR_PARTS)
53+
r'(?i)\s+l(?:ightness)?\((\+\s|\-\s|\*)?\s*({strict_percent})\s*\)'.format(**COLOR_PARTS)
5254
),
5355
"min-contrast_start": re.compile(r'(?i)\s+min-contrast\(\s*'),
5456
"blend_start": re.compile(r'(?i)\s+blenda?\(\s*'),
5557
"end": re.compile(r'(?i)\s*\)')
5658
}
5759

58-
RE_HUE = re.compile(r'(?i){angle}'.format(**parse.COLOR_PARTS))
60+
RE_HUE = re.compile(r'(?i){angle}'.format(**COLOR_PARTS))
5961
RE_COLOR_START = re.compile(r'(?i)color\(\s*')
60-
RE_BLEND_END = re.compile(r'(?i)\s+({strict_percent})(?:\s+(rgb|hsl|hwb))?\s*\)'.format(**parse.COLOR_PARTS))
62+
RE_BLEND_END = re.compile(r'(?i)\s+({strict_percent})(?:\s+(rgb|hsl|hwb))?\s*\)'.format(**COLOR_PARTS))
6163
RE_BRACKETS = re.compile(r'(?:(\()|(\))|[^()]+)')
62-
RE_MIN_CONTRAST_END = re.compile(r'(?i)\s+({strict_float})\s*\)'.format(**parse.COLOR_PARTS))
64+
RE_MIN_CONTRAST_END = re.compile(r'(?i)\s+({strict_float})\s*\)'.format(**COLOR_PARTS))
6365
RE_VARS = re.compile(r'(?i)(?:(?<=^)|(?<=[\s\t\(,/]))(var\(\s*([-\w][-\w\d]*)\s*\))(?!\()(?=[\s\t\),/]|$)')
6466

6567
HWB_MATCH = re.compile(
6668
r"""(?xi)
6769
\b(hwb)\(\s*
6870
(?:
6971
# Space separated format
70-
{angle}{space}{percent}{space}{percent}(?:{slash}(?:{percent}|{float}))? |
72+
{angle}{loose_space}{percent}{loose_space}{percent}(?:{slash}(?:{percent}|{float}))? |
7173
# comma separated format
7274
{angle}{comma}{percent}{comma}{percent}(?:{comma}(?:{percent}|{float}))?
7375
)
7476
\s*\)
75-
""".format(**parse.COLOR_PARTS)
77+
""".format(**COLOR_PARTS)
7678
)
7779

7880

@@ -188,7 +190,10 @@ def match(cls, string, start=0, fullmatch=True):
188190

189191
m = HWB_MATCH.match(string, start)
190192
if m is not None and (not fullmatch or m.end(0) == len(string)):
191-
return parse.parse_channels(string[m.end(1) + 1:m.end(0) - 1], cls.BOUNDS), m.end(0)
193+
return parse.parse_channels(
194+
list(RE_CHAN_VALUE.findall(string[m.end(1) + 1:m.end(0) - 1])),
195+
cls.CHANNELS, scaled=True
196+
), m.end(0)
192197
return None
193198

194199
@classmethod
@@ -198,8 +203,10 @@ def to_string(
198203
*,
199204
alpha=None,
200205
precision=None,
206+
percent: bool = True,
201207
fit=True,
202208
none=False,
209+
comma: bool = False,
203210
**kwargs
204211
) -> str:
205212
"""Convert to CSS."""
@@ -212,7 +219,9 @@ def to_string(
212219
fit=fit,
213220
none=none,
214221
color=kwargs.get('color', False),
215-
legacy=kwargs.get('comma', False)
222+
percent=True if comma else percent,
223+
scale=100,
224+
legacy=comma
216225
)
217226

218227

@@ -349,7 +358,7 @@ def adjust_base(self, base, string):
349358

350359
self._color = base
351360
pattern = "color({} {})".format(self._color.clone().clip().to_string(precision=-1), string)
352-
color, start = self._adjust(pattern)
361+
color, _ = self._adjust(pattern)
353362
if color is not None:
354363
self._color.update(color)
355364
else:
@@ -486,12 +495,12 @@ def min_contrast(self, color1, color2, target):
486495
if is_dark:
487496
primary = "whiteness"
488497
secondary = "blackness"
489-
min_mix = orig.whiteness * 100
498+
min_mix = orig[primary] * 100
490499
max_mix = 100
491500
else:
492501
primary = "blackness"
493502
secondary = "whiteness"
494-
min_mix = orig.blackness * 100
503+
min_mix = orig[primary] * 100
495504
max_mix = 100
496505
orig_ratio = ratio
497506
last_ratio = 0
@@ -620,13 +629,15 @@ def _parse(
620629
s = color
621630
space_class = cls.CS_MAP.get(s)
622631
if not space_class:
623-
raise ValueError("'{}' is not a registered color space")
632+
raise ValueError("'{}' is not a registered color space".format(s))
624633
num_channels = len(space_class.CHANNELS)
625-
if len(data) < num_channels:
626-
data = list(data) + [alg.NaN] * (num_channels - len(data))
634+
num_data = len(data)
635+
if num_data < num_channels:
636+
data = list(data) + [alg.NaN] * (num_channels - num_data)
627637
coords = [alg.clamp(float(v), *c.limit) for c, v in zipl(space_class.CHANNELS, data)]
628638
coords.append(alg.clamp(float(alpha), *space_class.channels[-1].limit))
629639
obj = space_class, coords
640+
630641
# Parse a CSS string
631642
else:
632643
m = cls._match(color, fullmatch=True, variables=variables)
@@ -635,18 +646,18 @@ def _parse(
635646
coords = [alg.clamp(float(v), *c.limit) for c, v in zipl(m[0].CHANNELS, m[1])]
636647
coords.append(alg.clamp(float(m[2]), *m[0].channels[-1].limit))
637648
obj = m[0], coords
649+
650+
# Handle a color instance
638651
elif isinstance(color, BASE):
639-
# Handle a color instance
640652
space_class = cls.CS_MAP.get(color.space())
641653
if not space_class:
642-
raise ValueError("'{}' is not a registered color space")
654+
raise ValueError("'{}' is not a registered color space".format(color.space()))
643655
obj = space_class, color[:]
656+
657+
# Handle a color dictionary
644658
elif isinstance(color, Mapping):
645-
# Handle a color dictionary
646-
space = color['space']
647-
coords = color['coords']
648-
alpha = color.get('alpha', 1.0)
649-
obj = cls._parse(space, coords, alpha)
659+
obj = cls._parse(color['space'], color['coords'], color.get('alpha', 1.0))
660+
650661
else:
651662
raise TypeError("'{}' is an unrecognized type".format(type(color)))
652663

@@ -710,15 +721,15 @@ def new(self, color, data=None, alpha=util.DEF_ALPHA, *, variables=None, **kwarg
710721

711722
return type(self)(color, data, alpha, variables=variables, **kwargs)
712723

713-
def update(self, color, data=None, alpha=util.DEF_ALPHA, *, variables=None, **kwargs):
724+
def update(self, color, data=None, alpha=util.DEF_ALPHA, *, norm=True, variables=None, **kwargs):
714725
"""Update the existing color space with the provided color."""
715726

716727
space = self.space()
717728
self._space, self._coords = self._parse(
718729
color, data=data, alpha=alpha, variables=variables, **kwargs
719730
)
720731
if self._space.NAME != space:
721-
self.convert(space, in_place=True)
732+
self.convert(space, in_place=True, norm=norm)
722733
return self
723734

724735
def mutate(self, color, data=None, alpha=util.DEF_ALPHA, *, variables=None, **kwargs):

custom/tmtheme.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
import re
55
from ColorHelper.ch_util import get_base_color
66

7-
RE_COMPRESS = re.compile(r'(?i)^#({hex})\1({hex})\2({hex})\3(?:({hex})\4)?$'.format(**parse.COLOR_PARTS))
7+
HEX = r'[a-f0-9]'
8+
9+
RE_COMPRESS = re.compile(r'(?i)^#({hex})\1({hex})\2({hex})\3(?:({hex})\4)?$'.format(hex=HEX))
810

911
MATCH = re.compile(
1012
r"""(?xi)
@@ -14,7 +16,7 @@
1416
# Names
1517
\b(?<!\#)[a-z][a-z0-9]{{2,}}(?!\()\b
1618
)
17-
""".format(**parse.COLOR_PARTS)
19+
""".format(hex=HEX)
1820
)
1921

2022
name2hex_map = {

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, 1, "final")
195+
__version_info__ = Version(2, 0, 1, "final")
196196
__version__ = __version_info__._get_canonical()

lib/coloraide/algebra.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,22 @@ def nlog(value: float) -> float:
164164
return math.copysign(1, value) * math.log(abs(value))
165165

166166

167+
def rect_to_polar(a: float, b: float) -> Tuple[float, float]:
168+
"""Take rectangular coordinates and make them polar."""
169+
170+
c = math.sqrt(a ** 2 + b ** 2)
171+
h = math.degrees(math.atan2(b, a)) % 360
172+
return c, h
173+
174+
175+
def polar_to_rect(c: float, h: float) -> Tuple[float, float]:
176+
"""Take rectangular coordinates and make them polar."""
177+
178+
a = c * math.cos(math.radians(h))
179+
b = c * math.sin(math.radians(h))
180+
return a, b
181+
182+
167183
################################
168184
# Interpolation and splines
169185
################################
@@ -481,7 +497,7 @@ def _cross_pad(a: ArrayLike, s: Tuple[int, ...]) -> Array:
481497
m = acopy(a)
482498

483499
# Initialize indexes so we can properly write our data
484-
total = prod(cast(Iterator[int], s[:-1]))
500+
total = prod(s[:-1])
485501
idx = [0] * (len(s) - 1)
486502

487503
for c in range(total):

0 commit comments

Comments
 (0)