From 08af99b57d246fffb7bd58f31d52ecd13716558f Mon Sep 17 00:00:00 2001 From: 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> Date: Sat, 8 Mar 2025 22:25:51 +1100 Subject: scheme: optimise dynamic scheme gen Make material schemes flavours of dynamic instead Remove dynamic-scheme subcommand Optimise scheme generation --- completions/caelestia.fish | 3 +- main.fish | 7 --- scheme/gen-scheme.fish | 27 ++++++--- scheme/genmaterial.py | 134 +++++++++++++++++++-------------------------- wallpaper.fish | 22 ++++++-- 5 files changed, 91 insertions(+), 102 deletions(-) diff --git a/completions/caelestia.fish b/completions/caelestia.fish index 2dc5675..b2a2916 100644 --- a/completions/caelestia.fish +++ b/completions/caelestia.fish @@ -1,6 +1,6 @@ set -l seen '__fish_seen_subcommand_from' set -l has_opt '__fish_contains_opt' -set -l commands help install shell toggle workspace-action scheme dynamic-scheme screenshot record clipboard clipboard-delete emoji-picker wallpaper pip +set -l commands help install shell toggle workspace-action scheme screenshot record clipboard clipboard-delete emoji-picker wallpaper pip set -l not_seen "not $seen $commands" # Disable file completions @@ -13,7 +13,6 @@ complete -c caelestia -n $not_seen -a 'shell' -d 'Start the shell or message it' complete -c caelestia -n $not_seen -a 'toggle' -d 'Toggle a special workspace' complete -c caelestia -n $not_seen -a 'workspace-action' -d 'Exec a dispatcher in the current group' complete -c caelestia -n $not_seen -a 'scheme' -d 'Switch the current colour scheme' -complete -c caelestia -n $not_seen -a 'dynamic-scheme' -d 'Change the dynamic colour scheme' complete -c caelestia -n $not_seen -a 'screenshot' -d 'Take a screenshot' complete -c caelestia -n $not_seen -a 'record' -d 'Take a screen recording' complete -c caelestia -n $not_seen -a 'clipboard' -d 'Open clipboard history' diff --git a/main.fish b/main.fish index ee126c6..bf27d6c 100755 --- a/main.fish +++ b/main.fish @@ -34,12 +34,6 @@ if test "$argv[1]" = scheme exit end -if test "$argv[1]" = dynamic-scheme - echo -n "$argv[2]" > $C_STATE/scheme/dynamic-scheme.txt - $src/wallpaper.fish -f $C_STATE/wallpaper/current - exit -end - if test "$argv[1]" = install set -l valid_modules scripts discord firefox fish foot fuzzel hypr safeeyes shell gtk vscode if test "$argv[2]" = all @@ -72,7 +66,6 @@ echo ' shell: start the shell or message it' echo ' toggle: toggle a special workspace' echo ' workspace-action: execute a Hyprland workspace dispatcher in the current group' echo ' scheme: change the current colour scheme' -echo ' dynamic-scheme: change the current dynamic material colour scheme' echo ' screenshot: take a screenshot' echo ' record: take a screen recording' echo ' clipboard: open clipboard history' diff --git a/scheme/gen-scheme.fish b/scheme/gen-scheme.fish index 7ac0d0e..4e82882 100755 --- a/scheme/gen-scheme.fish +++ b/scheme/gen-scheme.fish @@ -4,18 +4,27 @@ set -l src (dirname (status filename)) . $src/../util.fish -test -f "$argv[1]" && set -l img "$argv[1]" || set -l img $C_STATE/wallpaper/current -set -l img (realpath $img) +test -f "$argv[1]" && set -l img (realpath "$argv[1]") || set -l img $C_STATE/wallpaper/thumbnail.jpg contains -- "$argv[2]" light dark && set -l theme $argv[2] || set -l theme dark -test -n "$argv[3]" && set -l scheme $argv[3] || set -l scheme (cat $C_STATE/scheme/dynamic-scheme.txt 2> /dev/null || echo 'vibrant') + +set -l variants vibrant tonalspot expressive fidelity fruitsalad rainbow neutral content # Generate colours -if test $scheme = 'monochrome' - $src/autoadjust.py $theme $scheme (okolors $img -k 14) -else - test $theme = light && set -l lightness 50 || set -l lightness 70 - $src/autoadjust.py $theme $scheme (okolors $img -k 14 -w 0 -l $lightness) +test $theme = light && set -l lightness 50 || set -l lightness 70 +set -l colours (okolors $img -k 14 -w 0 -l $lightness) +for variant in $variants + mkdir -p $src/../data/schemes/dynamic/$variant + $src/autoadjust.py $theme $variant $colours > $src/../data/schemes/dynamic/$variant/$theme.txt end +mkdir -p $src/../data/schemes/dynamic/monochrome +$src/autoadjust.py $theme monochrome (okolors $img -k 14) > $src/../data/schemes/dynamic/monochrome/$theme.txt + +set -la variants monochrome # Generate layers and accents -$src/genmaterial.py $img $theme $scheme | head -c -1 # Trim trailing newline +set -l tmp (mktemp) +$src/genmaterial.py $img $theme > $tmp +for variant in $variants + grep -FA 15 $variant $tmp | tail -15 | head -c -1 >> $src/../data/schemes/dynamic/$variant/$theme.txt +end +rm $tmp diff --git a/scheme/genmaterial.py b/scheme/genmaterial.py index 0ac4c71..0fb067f 100755 --- a/scheme/genmaterial.py +++ b/scheme/genmaterial.py @@ -6,9 +6,17 @@ from colorsys import hls_to_rgb, rgb_to_hls from materialyoucolor.dynamiccolor.material_dynamic_colors import MaterialDynamicColors from materialyoucolor.hct import Hct -from materialyoucolor.quantize import QuantizeCelebi +from materialyoucolor.quantize import ImageQuantizeCelebi +from materialyoucolor.scheme.scheme_content import SchemeContent +from materialyoucolor.scheme.scheme_expressive import SchemeExpressive +from materialyoucolor.scheme.scheme_fidelity import SchemeFidelity +from materialyoucolor.scheme.scheme_fruit_salad import SchemeFruitSalad +from materialyoucolor.scheme.scheme_monochrome import SchemeMonochrome +from materialyoucolor.scheme.scheme_neutral import SchemeNeutral +from materialyoucolor.scheme.scheme_rainbow import SchemeRainbow +from materialyoucolor.scheme.scheme_tonal_spot import SchemeTonalSpot +from materialyoucolor.scheme.scheme_vibrant import SchemeVibrant from materialyoucolor.score.score import Score -from PIL import Image def darken(rgb: tuple[int, int, int], amount: float) -> tuple[int, int, int]: @@ -22,87 +30,55 @@ def mix( return tuple(round(rgb1[i] * (1 - amount) + rgb2[i] * amount) for i in range(3)) -def calculate_optimal_size( - width: int, height: int, bitmap_size: int = 128 -) -> (int, int): - image_area = width * height - bitmap_area = bitmap_size**2 - scale = math.sqrt(bitmap_area / image_area) if image_area > bitmap_area else 1 - return max(1, round(width * scale)), max(1, round(height * scale)) - - num_args = len(sys.argv) if num_args < 2: - print('Usage: [ "light" | "dark" ] [ ]') + print('Usage: [ "light" | "dark" ]') sys.exit(1) img = sys.argv[1] is_dark = num_args < 3 or sys.argv[2] != "light" -scheme = "vibrant" if num_args < 4 else sys.argv[3] - -with Image.open(sys.argv[1]) as image: - if image.format == "GIF": - image.seek(1) - - if image.mode in ["L", "P"]: - image = image.convert("RGB") - - width, height = image.size - opt_width, opt_height = calculate_optimal_size(width, height) - if opt_width < width or opt_height < height: - image = image.resize((opt_width, opt_height), Image.Resampling.BICUBIC) - colours = QuantizeCelebi(list(image.getdata()), 128) - - hct = Hct.from_int(Score.score(colours)[0]) - - -if scheme == "fruitsalad": - from materialyoucolor.scheme.scheme_fruit_salad import SchemeFruitSalad as Scheme -elif scheme == "expressive": - from materialyoucolor.scheme.scheme_expressive import SchemeExpressive as Scheme -elif scheme == "monochrome": - from materialyoucolor.scheme.scheme_monochrome import SchemeMonochrome as Scheme -elif scheme == "rainbow": - from materialyoucolor.scheme.scheme_rainbow import SchemeRainbow as Scheme -elif scheme == "tonalspot": - from materialyoucolor.scheme.scheme_tonal_spot import SchemeTonalSpot as Scheme -elif scheme == "neutral": - from materialyoucolor.scheme.scheme_neutral import SchemeNeutral as Scheme -elif scheme == "fidelity": - from materialyoucolor.scheme.scheme_fidelity import SchemeFidelity as Scheme -elif scheme == "content": - from materialyoucolor.scheme.scheme_content import SchemeContent as Scheme -else: - from materialyoucolor.scheme.scheme_vibrant import SchemeVibrant as Scheme - - -scheme = Scheme(hct, is_dark, 0.0) - - -colours = {} - -for color in vars(MaterialDynamicColors).keys(): - color_name = getattr(MaterialDynamicColors, color) - if hasattr(color_name, "get_hct"): - colours[color] = color_name.get_hct(scheme).to_rgba()[0:3] - -colours = { - "primary": colours["primary"], - "secondary": colours["secondary"], - "tertiary": colours["tertiary"], - "text": colours["onBackground"], - "subtext1": colours["onSurfaceVariant"], - "subtext0": colours["outline"], - "overlay2": mix(colours["surface"], colours["outline"], 0.86), - "overlay1": mix(colours["surface"], colours["outline"], 0.71), - "overlay0": mix(colours["surface"], colours["outline"], 0.57), - "surface2": mix(colours["surface"], colours["outline"], 0.43), - "surface1": mix(colours["surface"], colours["outline"], 0.29), - "surface0": mix(colours["surface"], colours["outline"], 0.14), - "base": colours["surface"], - "mantle": darken(colours["surface"], 0.03), - "crust": darken(colours["surface"], 0.05), -} -for name, colour in colours.items(): - print("{} {:02X}{:02X}{:02X}".format(name, *colour)) +colours = ImageQuantizeCelebi(img, 1, 128) +hct = Hct.from_int(Score.score(colours)[0]) + +for Scheme in ( + SchemeFruitSalad, + SchemeExpressive, + SchemeMonochrome, + SchemeRainbow, + SchemeTonalSpot, + SchemeNeutral, + SchemeFidelity, + SchemeContent, + SchemeVibrant, +): + print("\n" + Scheme.__name__[6:].lower()) + scheme = Scheme(hct, is_dark, 0.0) + + colours = {} + + for color in vars(MaterialDynamicColors).keys(): + color_name = getattr(MaterialDynamicColors, color) + if hasattr(color_name, "get_hct"): + colours[color] = color_name.get_hct(scheme).to_rgba()[:3] + + colours = { + "primary": colours["primary"], + "secondary": colours["secondary"], + "tertiary": colours["tertiary"], + "text": colours["onBackground"], + "subtext1": colours["onSurfaceVariant"], + "subtext0": colours["outline"], + "overlay2": mix(colours["surface"], colours["outline"], 0.86), + "overlay1": mix(colours["surface"], colours["outline"], 0.71), + "overlay0": mix(colours["surface"], colours["outline"], 0.57), + "surface2": mix(colours["surface"], colours["outline"], 0.43), + "surface1": mix(colours["surface"], colours["outline"], 0.29), + "surface0": mix(colours["surface"], colours["outline"], 0.14), + "base": colours["surface"], + "mantle": darken(colours["surface"], 0.03), + "crust": darken(colours["surface"], 0.05), + } + + for name, colour in colours.items(): + print("{} {:02X}{:02X}{:02X}".format(name, *colour)) diff --git a/wallpaper.fish b/wallpaper.fish index 24e5780..25c7090 100755 --- a/wallpaper.fish +++ b/wallpaper.fish @@ -106,13 +106,25 @@ else # Unload unused wallpapers to preserve memory hyprctl hyprpaper unload unused > /dev/null + # Thumbnail wallpaper for colour gen + set -l thumb_path $C_CACHE/thumbnails/(string replace -a '/' '-' (dirname $chosen_wallpaper | string sub -s 2))-(path change-extension '.jpg' (basename $chosen_wallpaper)) + if test -f $thumb_path + # Use thumbnail from shell + cp $thumb_path $state_dir/thumbnail.jpg + else + magick -define jpeg:size=256x256 $chosen_wallpaper -thumbnail 128x128 $state_dir/thumbnail.jpg + end + # Generate colour scheme for wallpaper set -l src (dirname (status filename)) - mkdir -p $src/data/schemes/dynamic - $src/scheme/gen-scheme.fish $chosen_wallpaper dark > $src/data/schemes/dynamic/dark.txt - $src/scheme/gen-scheme.fish $chosen_wallpaper light > $src/data/schemes/dynamic/light.txt - if test "$(cat $C_STATE/scheme/current-name.txt 2> /dev/null)" = 'dynamic' - caelestia scheme dynamic $_flag_T > /dev/null + $src/scheme/gen-scheme.fish $state_dir/thumbnail.jpg dark & + $src/scheme/gen-scheme.fish $state_dir/thumbnail.jpg light & + if test -f $C_STATE/scheme/current-name.txt + set -l variant (string match -gr 'dynamic-(.*)' (cat $C_STATE/scheme/current-name.txt)) + if test -n "$variant" + wait + caelestia scheme dynamic $variant $_flag_T > /dev/null + end end # Store the wallpaper chosen -- cgit v1.2.3-freya