diff options
Diffstat (limited to 'scheme/autoadjust.py')
| -rwxr-xr-x | scheme/autoadjust.py | 96 |
1 files changed, 92 insertions, 4 deletions
diff --git a/scheme/autoadjust.py b/scheme/autoadjust.py index a8632ac..db70138 100755 --- a/scheme/autoadjust.py +++ b/scheme/autoadjust.py @@ -1,27 +1,115 @@ #!/bin/python3 import sys +from math import sqrt from colorsys import rgb_to_hls, hls_to_rgb +light_colours = [ + "dc8a78", + "dd7878", + "ea76cb", + "8839ef", + "d20f39", + "e64553", + "fe640b", + "df8e1d", + "40a02b", + "179299", + "04a5e5", + "209fb5", + "1e66f5", + "7287fd", +] + +dark_colours = [ + "f5e0dc", + "f2cdcd", + "f5c2e7", + "cba6f7", + "f38ba8", + "eba0ac", + "fab387", + "f9e2af", + "a6e3a1", + "94e2d5", + "89dceb", + "74c7ec", + "89b4fa", + "b4befe", +] + def hex_to_rgb(hex: str) -> tuple[int, int, int]: """Convert a hex string to an RGB tuple in the range [0, 1].""" return tuple(int(hex[i:i+2], 16) / 255 for i in (0, 2, 4)) +def rgb_to_hex(rgb: tuple[int, int, int]) -> str: + """Convert an RGB tuple in the range [0, 1] to a hex string.""" + return "".join(f"{round(i * 255):02X}" for i in rgb) + def hex_to_hls(hex: str) -> tuple[float, float, float]: return rgb_to_hls(*hex_to_rgb(hex)) -def adjust_saturation(hex: str, amount: float,) -> str: +def adjust(hex: str, light: float = 0, sat: float = 0) -> str: h, l, s = hex_to_hls(hex) - s = max(0, min(1, s + amount)) - return "".join(f"{round(i * 255):02X}" for i in hls_to_rgb(h, l, s)) + l = max(0, min(1, l + light)) + s = max(0, min(1, s + sat)) + return rgb_to_hex(hls_to_rgb(h, l, s)) + +def distance(colour: str, base: str) -> float: + r1, g1, b1 = hex_to_rgb(colour) + r2, g2, b2 = hex_to_rgb(base) + return sqrt((r2 - r1)**2 + (g2 - g1)**2 + (b2 - b1)**2) + +def smart_sort(colours: list[str], base: list[str]) -> list[str]: + sorted_colours = [None] * len(colours) + distances = {} + + for colour in colours: + dist = [(i, distance(colour, b)) for i, b in enumerate(base)] + dist.sort(key=lambda x: x[1]) + distances[colour] = dist + + for colour in colours: + while len(distances[colour]) > 0: + i, dist = distances[colour][0] + + if sorted_colours[i] is None: + sorted_colours[i] = colour, dist + break + elif sorted_colours[i][1] > dist: + old = sorted_colours[i][0] + sorted_colours[i] = colour, dist + colour = old + + distances[colour].pop(0) + + return [i[0] for i in sorted_colours] + +def mix(a: str, b: str, w: float) -> str: + r1, g1, b1 = hex_to_rgb(a) + r2, g2, b2 = hex_to_rgb(b) + return rgb_to_hex((r1 * (1 - w) + r2 * w, g1 * (1 - w) + g2 * w, b1 * (1 - w) + b2 * w)) + +def mix_colours(colours: list[str], base: list[str], amount: float) -> list[str]: + for i, b in enumerate(base): + colours[i] = mix(colours[i], b, amount) if __name__ == "__main__": light = sys.argv[1] == "light" added_sat = 0.25 if light else 0.1 + base = light_colours if light else dark_colours + colours = [] for colour in sys.argv[3].split(" ")[1:]: - print(adjust_saturation(colour, added_sat)) + colours.append(adjust(colour, sat=added_sat)) # TODO: optional adjust + + colours = smart_sort(colours, base) # TODO: optional smart sort + + mix_colours(colours, base, 0.5) # TODO: customize mixing from config + + for colour in colours: + print(colour) for layer in sys.argv[4:]: print(layer.split(" ")[0]) |