1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
#!/usr/bin/env python3
#******************************************************************************
# Copyright (C) 2018 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
# This file is part of the thcolor project, which is MIT-licensed.
#******************************************************************************
""" Conversions between color systems. """
from math import ceil as _ceil
from colorsys import hls_to_rgb
__all__ = ["hls_to_hwb", "hwb_to_hls", "hls_to_rgb", "rgb_to_hls",
"rgb_to_hwb", "hwb_to_rgb", "netscape_color"]
# ---
# Color systems conversion utilities.
# ---
def hls_to_hwb(hue, s, l):
""" Convert HWB to HSL. """
# TODO
pass
def hwb_to_hls(hue, l, s):
""" Convert HWB to HLS. """
# TODO
pass
# `hls_to_rgb` is imported from the standard `colorsys` module.
def rgb_to_hls(r, g, b):
""" Convert RGB to HLS. """
# TODO
pass
def rgb_to_hwb(r, g, b):
""" Convert RGB to HWB. """
# TODO
pass
def hwb_to_rgb(hue, w, b):
""" Convert HWB to RGB color.
https://drafts.csswg.org/css-color/#hwb-to-rgb """
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)
return r, g, b
# ---
# Other utilities.
# ---
def netscape_color(name):
""" Produce a color from a name (which can be all-text, all-digits or
both), using the Netscape behaviour. """
# Find more about this here: https://stackoverflow.com/a/8333464
#
# First of all:
# - we sanitize our input by replacing invalid characters
# by '0' characters (the 0xFFFF limit is due to how
# UTF-16 was managed at the time).
# - we truncate our input to 128 characters.
name = name.lower()
name = ''.join(c if c in '0123456789abcdef' \
else ('0', '00')[ord(c) > 0xFFFF] \
for c in name[:128])[:128]
# Then we calculate some values we're going to need.
# `iv` is the size of the zone for a member.
# `sz` is the size of the digits slice to take in that zone
# (max. 8).
# `of` is the offset in the zone of the slice to take.
iv = _ceil(len(name) / 3)
of = iv - 8 if iv > 8 else 0
sz = iv - of
# Then we isolate the slices using the values calculated
# above. `gr` will be an array of 3 or 4 digit strings
# (depending on the number of members).
gr = list(map(lambda i: name[i * iv + of:i * iv + iv] \
.ljust(sz, '0'), range(3)))
# Check how many digits we can skip at the beginning of
# each slice.
pre = min(map(lambda x: len(x) - len(x.lstrip('0')), gr))
pre = min(pre, sz - 2)
# Then we extract the values.
it = map(lambda x: int('0' + x[pre:pre + 2], 16), gr)
r, g, b = it
return (r, g, b)
# End of file.
|