aboutsummaryrefslogtreecommitdiff
path: root/thcolor/_sys.py
blob: e40d885b7b67517ab2f302259556ecb675e89550 (plain)
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.