better color changing (maual)

This commit is contained in:
Lennart J. Kurzweg (Nx2)
2024-12-02 21:00:01 +01:00
parent a82660b049
commit f5538e69a5
3 changed files with 150 additions and 144 deletions

View File

@@ -5,17 +5,18 @@
<div class="color-container" style="border-color: ${color-set.base}"> <div class="color-container" style="border-color: ${color-set.base}">
<div class="color-box" style="background: ${color-set.dark}; height: ${builtins.toString size}px;"> <div class="color-box" style="background: ${color-set.dark}; height: ${builtins.toString size}px;">
<p style="color: ${color-set.bright}"> ${color-name}.dark </p> <p style="color: ${color-set.bright}"> ${color-name}.dark </p>
<p style="color: ${color-set.bright}"> ${color-set.dark} </p>
</div> </div>
<div class="color-box" style="background: ${color-set.base}; height: ${builtins.toString size}px;"> <div class="color-box" style="background: ${color-set.base}; height: ${builtins.toString size}px;">
<p class="dynamic-text"> ${color-name}.base </p> <p class="dynamic-text"> ${color-name}.base </p>
<p class="dynamic-text"> ${color-set.base} </p>
</div> </div>
<div class="color-box" style="background: ${color-set.bright}; height: ${builtins.toString size}px;"> <div class="color-box" style="background: ${color-set.bright}; height: ${builtins.toString size}px;">
<p style="color: ${color-set.dark}"> ${color-name}.bright </p> <p style="color: ${color-set.dark}"> ${color-name}.bright </p>
<p style="color: ${color-set.dark}"> ${color-set.bright} </p>
</div> </div>
</div> </div>
''; '';
in /* html */ '' in /* html */ ''
<!DOCTYPE html> <!DOCTYPE html>
<head> <head>
@@ -37,7 +38,7 @@
color: ${foreground}; color: ${foreground};
width: fit-content; width: fit-content;
margin: 10px auto 10px auto; margin: 10px auto 10px auto;
background: ${background}; background: rgba(${rice.lib.hex-to-rgb-comma-string background},${builtins.toString rice.transparency});
border: ${builtins.toString rice.border-width}px solid ${border}; border: ${builtins.toString rice.border-width}px solid ${border};
border-radius: ${builtins.toString rice.rounding}px; border-radius: ${builtins.toString rice.rounding}px;
padding: ${builtins.toString rice.gap-size}px; padding: ${builtins.toString rice.gap-size}px;
@@ -66,18 +67,20 @@
${cb accent "accent" 100} ${cb accent "accent" 100}
${cb secondary "secondary" 100} ${cb secondary "secondary" 100}
${cb tertiary "tertiary" 100} ${cb tertiary "tertiary" 100}
${cb weird "weird" 75} ${cb weird "weird" 100}
${cb special "special" 75} ${cb special "special" 100}
${cb positive "positive" 30} <br>
${cb negative "negative" 30} ${cb positive "positive" 70}
${cb black "black" 25} ${cb negative "negative" 70}
${cb white "white" 25} <br>
${cb blue "blue" 25} ${cb black "black" 50}
${cb cyan "cyan" 25} ${cb white "white" 50}
${cb green "green" 25} ${cb blue "blue" 50}
${cb magenta "magenta" 25} ${cb cyan "cyan" 50}
${cb red "red" 25} ${cb green "green" 50}
${cb yellow "yellow" 25} ${cb magenta "magenta" 50}
${cb red "red" 50}
${cb yellow "yellow" 50}
</body> </body>
<script> <script>
function getLuminance(color) { function getLuminance(color) {

View File

@@ -339,7 +339,7 @@ in {
"SUPER SHIFT, F5, exec, nx_gcal_event reauthenticate" "SUPER SHIFT, F5, exec, nx_gcal_event reauthenticate"
"SUPER, F6, exec, kitty -e 'htop'" "SUPER, F6, exec, kitty -e 'htop'"
"SUPER, F7, exec, kitty -e 'nmtui'" "SUPER, F7, exec, kitty -e 'nmtui'"
''SUPER, F8, exec, find ~/Pictures/wallpapers/* -type f -not -path "~/Pictures/wallpapers/.git/*" | sort -R | head -n 1 | xargs swww img --transition-type wipe --transition-angle 60 --transition-step 120 --transition-fps 120'' ''SUPER, F8, exec, find ~/Pictures/wallpapers/* -type f -not -path "~/Pictures/wallpapers/.git/*" | sort -R | head -n 1 | xargs -d '\n' swww img --transition-type wipe --transition-angle 60 --transition-step 120 --transition-fps 120 --transition-duration 2''
"SUPER, F9, execr, waybar_mode set '󰸉 '" "SUPER, F9, execr, waybar_mode set '󰸉 '"
"SUPER, F9, submap, color" "SUPER, F9, submap, color"
# "SUPER, F10, hyprload,update" # "SUPER, F10, hyprload,update"
@@ -571,9 +571,9 @@ in {
submap = reset submap = reset
submap = color submap = color
${action_simple { key = "W"; cmd = ''exec,kitty -e sh -c 'change_colors_json img $(swww query | sed -n 1p | sed -e "s-.*image: --g") && nh home switch' ''; }} ${action_simple { key = "W"; cmd = ''exec,swww query | sed -n 1p | sed -E 's-.*image: (.*)-"\1"-g' | xargs change_colors_json img && notify-send 'change_colors_json img successfull' ''; }}
${action_simple { key = "M"; cmd = ''exec,change_colors_json manual && kitty -e sh -c 'nh home switch && firefox /home/${user}/.config/color-pallete.html' ''; }} ${action_simple { key = "M"; cmd = ''exec,change_colors_json manual && notify-send 'change_colors_json manual successfull' ''; }}
${action_simple { key = "D"; cmd = ''exec,firefox /home/${user}/.config/color-pallete.html ''; }} ${action_simple { key = "D"; cmd = ''exec,firefox /home/${user}/.config/color-pallete.html''; }}
bind = , Escape, execr, waybar_mode unset bind = , Escape, execr, waybar_mode unset
bind = , Escape, submap, reset bind = , Escape, submap, reset
submap = reset submap = reset

View File

@@ -5,155 +5,158 @@
libraries = with python3Packages; [ numpy pillow scikit-learn ]; libraries = with python3Packages; [ numpy pillow scikit-learn ];
flakeIgnore = [ "E302" "E305" "E226" "E501" ]; flakeIgnore = [ "E302" "E305" "E226" "E501" ];
} /*python */ '' } /*python */ ''
from colorsys import hls_to_rgb, rgb_to_hls from colorsys import hls_to_rgb, rgb_to_hls
import json import json
import sys import sys
import subprocess import subprocess
from typing import Literal, cast from time import sleep
from numpy.typing import NDArray from typing import Literal, cast
from sklearn.cluster import KMeans from numpy.typing import NDArray
import numpy as np from sklearn.cluster import KMeans
from PIL import Image import numpy as np
from PIL import Image
def fc(c: int) -> str: def fc(c: int) -> str:
assert c < 256 assert c < 256
s = str(hex(c))[2:] s = str(hex(c))[2:]
if c < 16: if c < 16:
return "0" + s return "0" + s
elif len(s) == 1: elif len(s) == 1:
return s + s return s + s
else: else:
return s return s
class Color(object): class Color(object):
def __init__(self, rgb: tuple[int, ...], frequency: float = 1): def __init__(self, rgb: tuple[int, ...], frequency: float = 1):
assert len(rgb) == 3, "RGB values must be a tuple of length 3" assert len(rgb) == 3, "RGB values must be a tuple of length 3"
self.rgb = cast(tuple[int, int, int], rgb) self.rgb = cast(tuple[int, int, int], rgb)
self.freq: float = frequency self.freq: float = frequency
def __lt__(self, other: "Color") -> bool: def __lt__(self, other: "Color") -> bool:
return self.freq < other.freq return self.freq < other.freq
@property @property
def hls(self) -> tuple[float, float, float]: def hls(self) -> tuple[float, float, float]:
return rgb_to_hls(r=self.rgb[0] / 255, g=self.rgb[1] / 255, b=self.rgb[2] / 255) return rgb_to_hls(r=self.rgb[0] / 255, g=self.rgb[1] / 255, b=self.rgb[2] / 255)
@property @property
def luminance(self) -> float: def luminance(self) -> float:
return np.dot(np.array([0.2126, 0.7152, 0.0722]), self.rgb) return np.dot(np.array([0.2126, 0.7152, 0.0722]), self.rgb)
def k_means_extraction(arr: NDArray[float], height: int, width: int, palette_size: int) -> list[Color]: def k_means_extraction(arr: NDArray[float], height: int, width: int, palette_size: int) -> list[Color]:
arr = np.reshape(arr, (width * height, -1)) arr = np.reshape(arr, (width * height, -1))
model = KMeans(n_clusters=palette_size, n_init="auto", init="k-means++", random_state=2024) model = KMeans(n_clusters=palette_size, n_init="auto", init="k-means++", random_state=2024)
labels = model.fit_predict(arr) labels = model.fit_predict(arr)
palette = np.array(model.cluster_centers_, dtype=int) palette = np.array(model.cluster_centers_, dtype=int)
color_count = np.bincount(labels) color_count = np.bincount(labels)
color_frequency = color_count / float(np.sum(color_count)) color_frequency = color_count / float(np.sum(color_count))
colors = [] colors = []
for color, freq in zip(palette, color_frequency): for color, freq in zip(palette, color_frequency):
colors.append(Color(color, freq)) colors.append(Color(color, freq))
return colors return colors
class Palette: class Palette:
def __init__(self, colors: list[Color]): def __init__(self, colors: list[Color]):
self.colors = colors self.colors = colors
self.frequencies = [c.freq for c in colors] self.frequencies = [c.freq for c in colors]
def __getitem__(self, item: int) -> Color: def __getitem__(self, item: int) -> Color:
return self.colors[item] return self.colors[item]
def __len__(self) -> int: def __len__(self) -> int:
return self.number_of_colors return self.number_of_colors
def ensure_color(c: Color, alter_sat: bool) -> list[int]: def ensure_color(c: Color, alter_sat: bool) -> list[int]:
hue, lum, sat = c.hls hue, lum, sat = c.hls
if alter_sat: if alter_sat:
new_sat = min((sat**0.5) + 0.4, 1) new_sat = min((sat**0.5) + 0.4, 1)
else: else:
new_sat = sat new_sat = sat
new_lum = max(lum, 0.5) new_lum = max(lum, 0.5)
r, g, b = hls_to_rgb(h=hue, l=new_lum, s=new_sat) r, g, b = hls_to_rgb(h=hue, l=new_lum, s=new_sat)
return [int(r*255), int(g*255), int(b*255)] return [int(r*255), int(g*255), int(b*255)]
def list_to_hex(ilist: list[int]) -> str: def list_to_hex(ilist: list[int]) -> str:
return f"#{fc(ilist[0])}{fc(ilist[1])}{fc(ilist[2])}" return f"#{fc(ilist[0])}{fc(ilist[1])}{fc(ilist[2])}"
def alter_hue(ilist: list[int], hue: int) -> list[int]: def alter_hue(ilist: list[int], hue: int) -> list[int]:
assert hue >= 0 and hue <= 360 assert hue >= 0 and hue <= 360
r, g, b = ilist r, g, b = ilist
h, l, s = rgb_to_hls((r/255), (g/255), (b/255)) h, l, s = rgb_to_hls((r/255), (g/255), (b/255))
new_hue = (((h*360) + hue) % 360) / 360 new_hue = (((h*360) + hue) % 360) / 360
r, g, b = hls_to_rgb(h=new_hue, l=l, s=s) r, g, b = hls_to_rgb(h=new_hue, l=l, s=s)
return [int(r*255), int(g*255), int(b*255)] return [int(r*255), int(g*255), int(b*255)]
def alter_l(ilist: list[int], l_in_1_0: float) -> list[int]: def alter_l(ilist: list[int], l_in_1_0: float) -> list[int]:
assert l_in_1_0 >= 0 and l_in_1_0 <= 1 assert l_in_1_0 >= 0 and l_in_1_0 <= 1
r, g, b = ilist r, g, b = ilist
h, _, s = rgb_to_hls((r/255), (g/255), (b/255)) h, _, s = rgb_to_hls((r/255), (g/255), (b/255))
r, g, b = hls_to_rgb(h=h, l=l_in_1_0, s=s) r, g, b = hls_to_rgb(h=h, l=l_in_1_0, s=s)
return [int(r*255), int(g*255), int(b*255)] return [int(r*255), int(g*255), int(b*255)]
def extract_colors( def extract_colors(
image: str, image: str,
palette_size: int = 5, palette_size: int = 5,
resize: bool = True, resize: bool = True,
sort_mode: Literal["luminance", "frequency"] | None = None, sort_mode: Literal["luminance", "frequency"] | None = None,
) -> Palette: ) -> Palette:
img = Image.open(image).convert("RGB") img = Image.open(image).convert("RGB")
# open the image # open the image
img = img.resize((256, 256)) img = img.resize((256, 256))
width, height = img.size width, height = img.size
arr = np.asarray(img) arr = np.asarray(img)
colors = k_means_extraction(arr, height, width, palette_size) colors = k_means_extraction(arr, height, width, palette_size)
if sort_mode == "luminance": if sort_mode == "luminance":
colors.sort(key=lambda c: c.luminance, reverse=False) colors.sort(key=lambda c: c.luminance, reverse=False)
else: else:
colors.sort(reverse=True) colors.sort(reverse=True)
return Palette(colors) return Palette(colors)
def hyprpicker() -> Color: def hyprpicker() -> Color:
ret = str(subprocess.run(["${pkgs.hyprpicker}/bin/hyprpicker", "-f", "rgb"], capture_output=True).stdout)[2:-3] ret = str(subprocess.run(["${pkgs.hyprpicker}/bin/hyprpicker", "-n", "-f", "rgb"], capture_output=True).stdout)[2:-3]
return Color([int(c) for c in ret.split(" ")]) return Color([int(c) for c in ret.split(" ")])
if __name__ == "__main__": if __name__ == "__main__":
if sys.argv[1] == "img": if sys.argv[1] == "img":
img = sys.argv[2] img = sys.argv[2]
palette = extract_colors(image=img, palette_size=3) palette = extract_colors(image=img, palette_size=3)
accent = ensure_color(c=palette[0], alter_sat=False) accent = ensure_color(c=palette[0], alter_sat=False)
secondary = ensure_color(c=palette[1], alter_sat=True) secondary = ensure_color(c=palette[1], alter_sat=True)
tertiary = ensure_color(c=palette[2], alter_sat=False) tertiary = ensure_color(c=palette[2], alter_sat=False)
elif sys.argv[1] == "manual": elif sys.argv[1] == "manual":
accent = ensure_color(c=hyprpicker(), alter_sat=False) accent = ensure_color(c=hyprpicker(), alter_sat=False)
secondary = ensure_color(c=hyprpicker(), alter_sat=True) sleep(0.1)
tertiary = ensure_color(c=hyprpicker(), alter_sat=False) secondary = ensure_color(c=hyprpicker(), alter_sat=True)
sleep(0.1)
tertiary = ensure_color(c=hyprpicker(), alter_sat=False)
weird = alter_hue(ilist=accent, hue=80) weird = alter_hue(ilist=accent, hue=80)
special = alter_hue(ilist=accent, hue=180) special = alter_hue(ilist=accent, hue=180)
foreground = alter_l(accent, 0.9) foreground = alter_l(accent, 0.9)
background = alter_l(accent, 0.1) background = alter_l(accent, 0.1)
d = { d = {
"base": { "base": {
"foreground": list_to_hex(foreground), "foreground": list_to_hex(foreground),
"background": list_to_hex(background) "background": list_to_hex(background)
}, },
"to_alter": { "to_alter": {
"accent": list_to_hex(accent), "accent": list_to_hex(accent),
"secondary": list_to_hex(secondary), "secondary": list_to_hex(secondary),
"tertiary": list_to_hex(tertiary), "tertiary": list_to_hex(tertiary),
"special": list_to_hex(special), "special": list_to_hex(special),
"weird": list_to_hex(weird) "weird": list_to_hex(weird)
} }
} }
with open("/home/nx2/nix-dots/flake-modules/colors.json", "w") as f: with open("/home/nx2/nix-dots/flake-modules/colors.json", "w") as f:
f.write(json.dumps(d, indent=4)) f.write(json.dumps(d, indent=4))
'') '')
]; ];
} }