mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
feat(color): add HSV support to Color class
Add `Color.hsv` property and `Color.from_hsv` class method. This utilizes the existing `HSV` namedtuple which is currently unused.
This commit is contained in:
@@ -31,7 +31,7 @@ output = table
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import re
|
import re
|
||||||
from colorsys import hls_to_rgb, rgb_to_hls
|
from colorsys import hls_to_rgb, hsv_to_rgb, rgb_to_hls, rgb_to_hsv
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
from typing import Callable, NamedTuple
|
from typing import Callable, NamedTuple
|
||||||
@@ -82,7 +82,7 @@ class HSV(NamedTuple):
|
|||||||
s: float
|
s: float
|
||||||
"""Saturation in range 0 to 1."""
|
"""Saturation in range 0 to 1."""
|
||||||
v: float
|
v: float
|
||||||
"""Value un range 0 to 1."""
|
"""Value in range 0 to 1."""
|
||||||
|
|
||||||
|
|
||||||
class Lab(NamedTuple):
|
class Lab(NamedTuple):
|
||||||
@@ -212,6 +212,21 @@ class Color(NamedTuple):
|
|||||||
r, g, b = hls_to_rgb(h, l, s)
|
r, g, b = hls_to_rgb(h, l, s)
|
||||||
return cls(int(r * 255 + 0.5), int(g * 255 + 0.5), int(b * 255 + 0.5))
|
return cls(int(r * 255 + 0.5), int(g * 255 + 0.5), int(b * 255 + 0.5))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_hsv(cls, h: float, s: float, v: float) -> Color:
|
||||||
|
"""Create a color from HSV components.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
h: Hue.
|
||||||
|
s: Saturation.
|
||||||
|
v: Value.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A new color.
|
||||||
|
"""
|
||||||
|
r, g, b = hsv_to_rgb(h, s, v)
|
||||||
|
return cls(int(r * 255 + 0.5), int(g * 255 + 0.5), int(b * 255 + 0.5))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def inverse(self) -> Color:
|
def inverse(self) -> Color:
|
||||||
"""The inverse of this color.
|
"""The inverse of this color.
|
||||||
@@ -286,6 +301,19 @@ class Color(NamedTuple):
|
|||||||
h, l, s = rgb_to_hls(r, g, b)
|
h, l, s = rgb_to_hls(r, g, b)
|
||||||
return HSL(h, s, l)
|
return HSL(h, s, l)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def hsv(self) -> HSV:
|
||||||
|
"""This color in HSV format.
|
||||||
|
|
||||||
|
HSV color is an alternative way of representing a color, which can be used in certain color calculations.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Color encoded in HSV format.
|
||||||
|
"""
|
||||||
|
r, g, b = self.normalized
|
||||||
|
h, s, v = rgb_to_hsv(r, g, b)
|
||||||
|
return HSV(h, s, v)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def brightness(self) -> float:
|
def brightness(self) -> float:
|
||||||
"""The human perceptual brightness.
|
"""The human perceptual brightness.
|
||||||
|
|||||||
@@ -52,6 +52,17 @@ def test_hsl():
|
|||||||
assert red.hsl.css == "hsl(356,81.8%,43.1%)"
|
assert red.hsl.css == "hsl(356,81.8%,43.1%)"
|
||||||
|
|
||||||
|
|
||||||
|
def test_hsv():
|
||||||
|
red = Color(200, 20, 32)
|
||||||
|
print(red.hsv)
|
||||||
|
assert red.hsv == pytest.approx(
|
||||||
|
(0.9888888888888889, 0.8999999999999999, 0.7843137254901961)
|
||||||
|
)
|
||||||
|
assert Color.from_hsv(
|
||||||
|
0.9888888888888889, 0.8999999999999999, 0.7843137254901961
|
||||||
|
).normalized == pytest.approx(red.normalized, rel=1e-5)
|
||||||
|
|
||||||
|
|
||||||
def test_color_brightness():
|
def test_color_brightness():
|
||||||
assert Color(255, 255, 255).brightness == 1
|
assert Color(255, 255, 255).brightness == 1
|
||||||
assert Color(0, 0, 0).brightness == 0
|
assert Color(0, 0, 0).brightness == 0
|
||||||
|
|||||||
Reference in New Issue
Block a user