aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Touhey <thomas@touhey.fr>2019-05-10 11:40:49 +0200
committerThomas Touhey <thomas@touhey.fr>2019-05-10 11:40:49 +0200
commitd4c11d05f31c4e28c5af8988cf3e4d2b743de806 (patch)
tree0adf4c1c5b4d8dd9d9ec3fd978744812cd07ea37
parenta3a97576e40749ae6ba6cfa1735aa05e63cc2905 (diff)
Corrected formulas, now passes all tests!
-rwxr-xr-xtests/test_text.py8
-rwxr-xr-xthcolor/_color.py36
-rwxr-xr-xthcolor/_sys.py116
3 files changed, 119 insertions, 41 deletions
diff --git a/tests/test_text.py b/tests/test_text.py
index a923842..eb3d5c3 100755
--- a/tests/test_text.py
+++ b/tests/test_text.py
@@ -23,9 +23,9 @@ def _deg(value):
('rgba(1,22,242,0.500)', ( 1, 22, 242, 0.50)),
('rbga(5, 7)', ( 5, 0, 7, 1.00)),
('hsl(0, 1,50.0%)', (255, 0, 0, 1.00)),
- ('hls(0 / 1 0.5 , 0.2)', (255, 0, 0, 0.20)),
+ ('hls(0 / 1 0.5 , 0.2)', (255, 255, 255, 0.20)),
('hwb(0 0% 0)', (255, 0, 0, 1.00)),
- ('hbw(127 .5)', (128, 255, 142, 1.00)),
+ ('hbw(127 .5)', ( 0, 128, 15, 1.00)),
('gray(100)', (100, 100, 100, 1.00)),
('gray(100 / 55 %)', (100, 100, 100, 0.55)),
('gray(red( #123456 )/0.2/)', ( 18, 18, 18, 0.20)),
@@ -39,8 +39,8 @@ def test_rgba(test_input, expected):
('lighter(50%, hsl(0, 1, 60.0%))', (_deg( 0), 1.00, 1.00, 1.00)),
('saturate(10%, hls(0, 1, 85.0%))', (_deg( 0), 0.95, 1.00, 1.00)),
('desaturate(10%, hls(0, 1, 5%, 0.2))', (_deg( 0), 0.00, 1.00, 0.20)),
- ('rgba(255, 0, 0, 20 %)', (_deg( 0), 0.50, 1.00, 0.20)),
- ('Y40, 33%, 55%', (_deg(84), 0.15, 0.39, 1.00)),
+ ('rgba(255, 0, 0, 20 %)', (_deg( 0), 1.00, 0.50, 0.20)),
+ ('Y40, 33%, 55%', (_deg(84), 0.16, 0.39, 1.00)),
))
def test_hsla(test_input, expected):
assert Color.from_text(test_input).hsla() == expected
diff --git a/thcolor/_color.py b/thcolor/_color.py
index 63b35d5..7850ac4 100755
--- a/thcolor/_color.py
+++ b/thcolor/_color.py
@@ -383,13 +383,9 @@ class Color:
if self._type == Color.Type.RGB:
return (self._r, self._g, self._b)
elif self._type == Color.Type.HSL:
- r, g, b = map(lambda x: int(x * 255),
- _hls_to_rgb(self._hue.turns % 1, self._lgt, self._sat))
- return (r, g, b)
+ return _hls_to_rgb(self._hue, self._lgt, self._sat)
elif self._type == Color.Type.HWB:
- r, g, b = map(lambda x: int(x * 255),
- _hwb_to_rgb(self._hue.turns % 1, self._wht, self._blk))
- return (r, g, b)
+ return _hwb_to_rgb(self._hue, self._wht, self._blk)
raise ValueError(f"color type {self._type} doesn't translate to rgb")
@@ -397,13 +393,11 @@ class Color:
""" Get the (hue, saturation, lightness) components of the color. """
if self._type == Color.Type.RGB:
- h, l, s = _rgb_to_hls(self._r, self._g, self._b)
- return (_Angle(_Angle.Type.TURN, h), s, l)
+ return _rgb_to_hls(self._r, self._g, self._b)
elif self._type == Color.Type.HSL:
return (self._hue, self._sat, self._lgt)
elif self._type == Color.Type.HWB:
- h, l, s = _hwb_to_hls(self._hue.turns % 1, self._wht, self._blk)
- return (_Angle(_Angle.Type.TURN, h), s, l)
+ return _hwb_to_hls(self._hue, self._wht, self._blk)
raise ValueError(f"color type {self._type} doesn't translate to hsl")
@@ -411,11 +405,9 @@ class Color:
""" Get the (hue, whiteness, blackness) components of the color. """
if self._type == Color.Type.RGB:
- h, w, b = _rgb_to_hwb(self._r, self._g, self._b)
- return (_Angle(_Angle.Type.TURN, h), w, b)
+ return _rgb_to_hwb(self._r, self._g, self._b)
elif self._type == Color.Type.HSL:
- h, w, b = _hls_to_hwb(self._hue.turns % 1, self._lgt, self._sat)
- return (_Angle(_Angle.Type.TURN, h), w, b)
+ return _hls_to_hwb(self._hue, self._lgt, self._sat)
elif self._type == Color.Type.HWB:
return (self._hue, self._wht, self._blk)
@@ -448,6 +440,14 @@ class Color:
h, s, l, a = self.hsla()
return (h, l, s, a)
+ def hwba(self):
+ """ Get the (hue, whiteness, blackness, alpha) components of
+ the color. """
+
+ h, w, b = self.hwb()
+ a = self._alpha
+ return (h, w, b, a)
+
def css(self):
""" Get the CSS declarations (with compatibility management). """
@@ -471,17 +471,17 @@ class Color:
l = round(self._lgt, 5) * 100
if a < 1.0:
- yield f'hsla({self._hue}, {s}%, {l}%, {a})'
+ yield f'hsla({self._hue.degrees}deg, {s}%, {l}%, {a})'
else:
- yield f'hsl({self._hue}, {s}%, {l}%)'
+ yield f'hsl({self._hue.degrees}deg, {s}%, {l}%)'
elif self._type == Type.HWB:
w = round(self._wht, 5) * 100
b = round(self._blk, 5) * 100
if a < 1.0:
- yield f'hwba({self._hue}, {w}%, {b}%, {a})'
+ yield f'hwba({self._hue.degrees}deg, {w}%, {b}%, {a})'
else:
- yield f'hwb({self._hue}, {w}%, {b}%)'
+ yield f'hwb({self._hue.degrees}deg, {w}%, {b}%)'
return list(statements())
diff --git a/thcolor/_sys.py b/thcolor/_sys.py
index e40d885..dbcf001 100755
--- a/thcolor/_sys.py
+++ b/thcolor/_sys.py
@@ -6,7 +6,8 @@
""" Conversions between color systems. """
from math import ceil as _ceil
-from colorsys import hls_to_rgb
+
+from ._angle import Angle as _Angle
__all__ = ["hls_to_hwb", "hwb_to_hls", "hls_to_rgb", "rgb_to_hls",
"rgb_to_hwb", "hwb_to_rgb", "netscape_color"]
@@ -15,41 +16,118 @@ __all__ = ["hls_to_hwb", "hwb_to_hls", "hls_to_rgb", "rgb_to_hls",
# Color systems conversion utilities.
# ---
-def hls_to_hwb(hue, s, l):
+def _rgb(r, g, b):
+ return tuple(map(lambda x: int(round(x * 255, 0)), (r, g, b)))
+def _hls(hue, s, l):
+ return _Angle(_Angle.Type.DEG, round(hue, 2)), round(l, 2), round(s, 2)
+
+def hls_to_hwb(hue, l, s):
""" Convert HWB to HSL. """
- # TODO
- pass
+ _, w, b = rgb_to_hwb(*hls_to_rgb(hue, l, s))
+ return (hue, w, b)
-def hwb_to_hls(hue, l, s):
+def hwb_to_hls(hue, w, b):
""" Convert HWB to HLS. """
- # TODO
- pass
+ _, l, s = rgb_to_hls(*hwb_to_rgb(hue, w, b))
+ return (hue, l, s)
+
+def hls_to_rgb(hue, l, s):
+ """ Convert HLS to RGB. """
+
+ if s == 0:
+ # Achromatic color.
+
+ return l, l, l
+
+ def _hue_to_rgb(t1, t2, hue):
+ hue %= 6
+
+ if hue < 1:
+ return t1 + (t2 - t1) * hue
+ elif hue < 3:
+ return t2
+ elif hue < 4:
+ return t1 + (t2 - t1) * (4 - hue)
+ return t1
+
+ hue = (hue.degrees % 360) / 60
+ if l <= 0.5:
+ t2 = l * (s + 1)
+ else:
+ t2 = l + s - (l * s)
-# `hls_to_rgb` is imported from the standard `colorsys` module.
+ t1 = l * 2 - t2
+
+ return _rgb(\
+ _hue_to_rgb(t1, t2, hue + 2),
+ _hue_to_rgb(t1, t2, hue),
+ _hue_to_rgb(t1, t2, hue - 2))
+
+def hwb_to_rgb(hue, w, bl):
+ """ Convert HWB to RGB color.
+ https://drafts.csswg.org/css-color/#hwb-to-rgb """
+
+ r, g, b = map(lambda x: x / 255, hls_to_rgb(hue, 0.5, 1.0))
+ if w + bl > 1:
+ w, bl = map(lambda x: x / (w + bl), (w, bl))
+ return _rgb(*map(lambda x: x * (1 - w - bl) + w, (r, g, b)))
def rgb_to_hls(r, g, b):
""" Convert RGB to HLS. """
- # TODO
- pass
+ r, g, b = map(lambda x: x / 255, (r, g, b))
+
+ min_value = min((r, g, b))
+ max_value = max((r, g, b))
+ chroma = max_value - min_value
+
+ if chroma == 0:
+ hue = 0
+ elif r == max_value:
+ hue = (g - b) / chroma
+ elif g == max_value:
+ hue = (b - r) / chroma + 2
+ else:
+ hue = (r - g) / chroma + 4
+
+ hue = hue * 60 + (hue < 0) * 360
+ l = (min_value + max_value) / 2
+ if min_value == max_value:
+ s = 0
+ else:
+ s = max_value - min_value
+ if l < 0.5:
+ s /= max_value + min_value
+ else:
+ s /= 2 - max_value - min_value
+
+ return _hls(hue, l, s)
def rgb_to_hwb(r, g, b):
""" Convert RGB to HWB. """
- # TODO
- pass
+ r, g, b = map(lambda x: x / 255, (r, g, b))
-def hwb_to_rgb(hue, w, b):
- """ Convert HWB to RGB color.
- https://drafts.csswg.org/css-color/#hwb-to-rgb """
+ max_value = max((r, g, b))
+ min_value = min((r, g, b))
+ chroma = max_value - min_value
+
+ if chroma == 0:
+ hue = 0
+ elif r == max_value:
+ hue = (g - b) / chroma
+ elif g == max_value:
+ hue = (b - r) / chroma + 2
+ elif g == max_value:
+ hue = (r - g) / chroma + 4
- r, g, b = hls_to_rgb(hue, 0.5, 1.0)
- f = lambda x: x * (1 - w - b) + w
- r, g, b = f(r), f(g), f(b)
+ hue = (hue % 6) * 360
+ w = min_value
+ b = max_value
- return r, g, b
+ return _Angle(_Angle.Type.DEG, hue), w, b
# ---
# Other utilities.