diff options
-rwxr-xr-x | tests/test_rgba.py | 8 | ||||
-rwxr-xr-x | thcolor/_builtin/_css.py | 188 | ||||
-rwxr-xr-x | thcolor/_builtin/_default.py | 10 | ||||
-rwxr-xr-x | thcolor/_color.py | 25 | ||||
-rwxr-xr-x | thcolor/_ref.py | 7 |
5 files changed, 152 insertions, 86 deletions
diff --git a/tests/test_rgba.py b/tests/test_rgba.py index f6af1f9..07614e2 100755 --- a/tests/test_rgba.py +++ b/tests/test_rgba.py @@ -19,7 +19,13 @@ from thcolor import Color (' rgb (1,22, 242 , 50.0% )', ( 1, 22, 242, 0.5)), ('rgba(1,22,242,0.500)', ( 1, 22, 242, 0.5)), ('rbga(5, 7)', ( 5, 0, 7, 1.0)), - ('hsl(0, 1,50.0%)', (255, 0, 0, 1.0)))) + ('hsl(0, 1,50.0%)', (255, 0, 0, 1.0)), + ('hls(0 / 1 0.5 , 0.2)', (255, 0, 0, 0.2)), + ('hwb(0 0% 0)', (255, 0, 0, 1.0)), + ('hbw(127 .5)', (128, 255, 142, 1.0)), + ('gray(100)', (100, 100, 100, 1.0)), + ('gray(100 / 55 %)', (100, 100, 100, 0.55)), +)) def test_rgba(test_input, expected): assert Color.from_text(test_input).rgba() == expected diff --git a/thcolor/_builtin/_css.py b/thcolor/_builtin/_css.py index a875907..45449ed 100755 --- a/thcolor/_builtin/_css.py +++ b/thcolor/_builtin/_css.py @@ -20,6 +20,10 @@ class CSS1Reference(_Reference): """ Named colors from CSS Level 1: https://www.w3.org/TR/CSS1/ """ + number = _Reference.number + percentage = _Reference.percentage + color = _Reference.color + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -55,6 +59,45 @@ class CSS1Reference(_Reference): except: return super()._color(name) + # --- + # Utilities. + # --- + + def _rgb(self, rgba, rgb_indexes): + r, g, b, alpha = rgba + ri, gi, bi = rgb_indexes + + try: + r = r.to_byte() + except ValueError as e: + raise _InvalidArgumentValueError(ri, str(e)) + + try: + g = g.to_byte() + except ValueError as e: + raise _InvalidArgumentValueError(gi, str(e)) + + try: + b = b.to_byte() + except ValueError as e: + raise _InvalidArgumentValueError(bi, str(e)) + + try: + alpha = alpha.to_factor() + except ValueError as e: + raise _InvalidArgumentValueError(3, str(e)) + + return _Reference.color(_Color(_Color.Type.RGB, r, g, b, alpha)) + + # --- + # Functions. + # --- + + def rgb(self, r: number | percentage, + g: number | percentage = number(0), + b: number | percentage = number(0)): + return self._rgb((r, g, b, 1.0), (0, 1, 2)) + class CSS2Reference(CSS1Reference): """ Named colors from CSS Level 2 (Revision 1): https://www.w3.org/TR/CSS2/ """ @@ -79,6 +122,11 @@ class CSS3Reference(CSS2Reference): """ Named colors from CSS Color Module Level 3: https://drafts.csswg.org/css-color-3/ """ + number = _Reference.number + percentage = _Reference.percentage + angle = _Reference.angle + color = _Reference.color + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -224,61 +272,10 @@ class CSS3Reference(CSS2Reference): except: return super()._color(name) -class CSS4Reference(CSS3Reference): - """ Named colors from CSS Color Module Level 4: - https://drafts.csswg.org/css-color/ """ - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - number = _Reference.number - percentage = _Reference.percentage - angle = _Reference.angle - color = _Reference.color - - # --- - # Named colors. - # --- - - __colors = { - 'rebeccapurple': _rgb('#663399')} - - def _color(self, name): - try: - return self.__colors[name] - except: - return super()._color(name) - # --- # Utilities. # --- - def _rgb(self, rgba, rgb_indexes): - r, g, b, alpha = rgba - ri, gi, bi = rgb_indexes - - try: - r = r.to_byte() - except ValueError as e: - raise _InvalidArgumentValueError(ri, str(e)) - - try: - g = g.to_byte() - except ValueError as e: - raise _InvalidArgumentValueError(gi, str(e)) - - try: - b = b.to_byte() - except ValueError as e: - raise _InvalidArgumentValueError(bi, str(e)) - - try: - alpha = alpha.to_factor() - except ValueError as e: - raise _InvalidArgumentValueError(3, str(e)) - - return _Reference.color(_Color(_Color.Type.RGB, r, g, b, alpha)) - def _hsl(self, hsla, hsl_indexes): h, s, l, alpha = hsla hi, si, li = hsl_indexes @@ -305,6 +302,57 @@ class CSS4Reference(CSS3Reference): return _Reference.color(_Color(_Color.Type.HSL, h, s, l, alpha)) + # --- + # Functions. + # --- + + def rgb(self, r: number | percentage, + g: number | percentage = number(0), b: number | percentage = number(0), + alpha: number | percentage = number(1.0)): + return self._rgb((r, g, b, alpha), (0, 1, 2)) + + def rgba(self, r: number | percentage, + g: number | percentage = number(0), b: number | percentage = number(0), + alpha: number | percentage = number(1.0)): + return self._rgb((r, g, b, alpha), (0, 1, 2)) + + def hsl(self, h: number | angle, s: number | percentage, + l: number | percentage, alpha: number | percentage = number(1.0)): + return self._hsl((h, s, l, alpha), (0, 1, 2)) + + def hsla(self, h: number | angle, s: number | percentage, + l: number | percentage, alpha: number | percentage = number(1.0)): + return self._hsl((h, s, l, alpha), (0, 1, 2)) + +class CSS4Reference(CSS3Reference): + """ Named colors from CSS Color Module Level 4: + https://drafts.csswg.org/css-color/ """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + number = _Reference.number + percentage = _Reference.percentage + angle = _Reference.angle + color = _Reference.color + + # --- + # Named colors. + # --- + + __colors = { + 'rebeccapurple': _rgb('#663399')} + + def _color(self, name): + try: + return self.__colors[name] + except: + return super()._color(name) + + # --- + # Utilities. + # --- + def _hwb(self, hwba, hwb_indexes): h, w, b, alpha = hwba hi, wi, bi = hwb_indexes @@ -335,31 +383,28 @@ class CSS4Reference(CSS3Reference): # Functions. # --- - def rgb(self, r: number | percentage, - g: number | percentage = number(0), b: number | percentage = number(0), + def hwb(self, h: number | angle, w: number | percentage = number(0), + b: number | percentage = number(0), alpha: number | percentage = number(1.0)): - return self._rgb((r, g, b, alpha), (0, 1, 2)) + return self._hwb((h, w, b, alpha), (0, 1, 2)) - def rgba(self, r: number | percentage, - g: number | percentage = number(0), b: number | percentage = number(0), + def hwba(self, h: number | angle, w: number | percentage = number(0), + b: number | percentage = number(0), alpha: number | percentage = number(1.0)): - return self._rgb((r, g, b, alpha), (0, 1, 2)) - - def hsl(self, h: number | angle, s: number | percentage, - l: number | percentage, alpha: number | percentage = number(1.0)): - return self._hsl((h, s, l, alpha), (0, 1, 2)) + return self._hwb((h, w, b, alpha), (0, 1, 2)) - def hsla(self, h: number | angle, s: number | percentage, - l: number | percentage, alpha: number | percentage = number(1.0)): - return self._hsl((h, s, l, alpha), (0, 1, 2)) + def gray(self, g: number | percentage, alpha: percentage = number(1.0)): + try: + g = g.to_byte() + except ValueError as e: + raise _InvalidArgumentValueError(0, str(e)) - def hwb(self, h: number | angle, w: number | percentage, - b: number | percentage, alpha: number | percentage = number(1.0)): - return self._hwb((h, w, b, alpha), (0, 1, 2)) + try: + alpha = alpha.to_factor() + except ValueError as e: + raise _InvalidArgumentValueError(1, str(e)) - def hwba(self, h: number | angle, w: number | percentage, - b: number | percentage, alpha: number | percentage = number(1.0)): - return self._hwb((h, w, b, alpha), (0, 1, 2)) + return _Reference.color(_Color(_Color.Type.RGB, g, g, g, alpha)) def lab(self, l: number, a: number, b: number, alpha: percentage = number(1.0)): @@ -369,7 +414,4 @@ class CSS4Reference(CSS3Reference): alpha: percentage = number(1.0)): raise NotImplementedError - def gray(self, g: number, alpha: percentage = number(1.0)): - raise NotImplementedError - # End of file. diff --git a/thcolor/_builtin/_default.py b/thcolor/_builtin/_default.py index d6004be..c34243b 100755 --- a/thcolor/_builtin/_default.py +++ b/thcolor/_builtin/_default.py @@ -84,4 +84,14 @@ class DefaultReference(_CSS4Reference): s: number | percentage, alpha: number | percentage = number(1.0)): return self._hsl((h, s, l, alpha), (0, 2, 1)) + def hbw(self, h: number | angle, b: number | percentage = number(0), + w: number | percentage = number(0), + alpha: number | percentage = number(1.0)): + return self._hwb((h, w, b, alpha), (0, 2, 1)) + + def hbwa(self, h: number | angle, b: number | percentage = number(0), + w: number | percentage = number(0), + alpha: number | percentage = number(1.0)): + return self._hwb((h, w, b, alpha), (0, 2, 1)) + # End of file. diff --git a/thcolor/_color.py b/thcolor/_color.py index 76dc505..04dd19f 100755 --- a/thcolor/_color.py +++ b/thcolor/_color.py @@ -302,16 +302,12 @@ class Color: if self._type == Color.Type.RGB: return (self._r, self._g, self._b) elif self._type == Color.Type.HSL: - r, g, b = _hls_to_rgb(self._hue.turns % 1, self._lgt, self._sat) - r *= 255 - g *= 255 - b *= 255 + r, g, b = map(lambda x: int(x * 255), + _hls_to_rgb(self._hue.turns % 1, self._lgt, self._sat)) return (r, g, b) elif self._type == Color.Type.HWB: - r, g, b = _hwb_to_rgb(self._hue.turns % 1, self._wht, self._blk) - r *= 255 - g *= 255 - b *= 255 + r, g, b = map(lambda x: int(x * 255), + _hwb_to_rgb(self._hue.turns % 1, self._wht, self._blk)) return (r, g, b) raise ValueError(f"color type {self._type} doesn't translate to rgb") @@ -333,6 +329,7 @@ class Color: # notation if the alpha value isn't 1.0. r, g, b, a = self.rgba() + a = round(a, 3) yield f'#{r:02X}{g:02X}{b:02X}' if a < 1.0: @@ -344,11 +341,19 @@ class Color: if self._type == Type.HSL: s = round(self._sat, 5) * 100 l = round(self._lgt, 5) * 100 - yield f'hsl({self._hue}, {s}%, {l}%)' + + if a < 1.0: + yield f'hsla({self._hue}, {s}%, {l}%, {a})' + else: + yield f'hsl({self._hue}, {s}%, {l}%)' elif self._type == Type.HWB: w = round(self._wht, 5) * 100 b = round(self._blk, 5) * 100 - yield f'hwb({self._hue}, {w}%, {b}%)' + + if a < 1.0: + yield f'hwba({self._hue}, {w}%, {b}%, {a})' + else: + yield f'hwb({self._hue}, {w}%, {b}%)' return list(statements()) diff --git a/thcolor/_ref.py b/thcolor/_ref.py index 5bc51c1..9c8a017 100755 --- a/thcolor/_ref.py +++ b/thcolor/_ref.py @@ -139,13 +139,16 @@ class Reference: def __init__(self, value): self._value = value - assert 0 <= value <= 100 + if value < 0: + value = 0 + + # value can actually be more than 100. def __repr__(self): return f"{self._value} %" def to_byte(self): - return int(self._value / 100 * 255) + return int(min(self._value / 100, 1.0) * 255) def to_factor(self): try: |