diff --git a/.download.sh b/.download.sh new file mode 100755 index 0000000..1384f5b --- /dev/null +++ b/.download.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +url="" +file_name="" + +read -p "Image URL: " url +read -p "Output File: " file_name + +if [ -z url ]; then + echo "Please input a image source URL" + echo "Abortung..." +fi + + +if [ -z file_name ]; then + echo "Please input a image target file name" + echo "Abortung..." +fi + +cd /home/jan/wallpapers/originals/ +curl -o "$file_name.jpg" $url +magick "$file_name.jpg" -resize 1920x1200 "/home/jan/wallpapers/$file_name.jpg" diff --git a/.paintr b/.paintr new file mode 100755 index 0000000..c9050b1 --- /dev/null +++ b/.paintr @@ -0,0 +1,358 @@ +#!/usr/bin/env python3 + +import argparse +import logging +import os +from pathlib import Path +import sys + +try: + from PIL import Image + import numpy as np + from skimage.color import rgb2lab, lab2rgb + import pytoml +except ImportError: + print("Dependencies not found. Please install them with 'pip install Pillow scikit-image numpy pytoml'", file=sys.stderr) + sys.exit(1) + +# --- Configuration & Setup --- + +APP_NAME = "paintr" +LOG_LEVELS = ["FATAL", "ERROR", "WARN", "INFO", "DEBUG"] + +# Default theme data embedded in the script for first-run setup. +DEFAULT_THEME_NAME = "catppuccin" +DEFAULT_THEME_CONTENT = """[data] +name = "Catppuccin" +version = "1.0" +variant = "dark" + +[colors] +background = "#1e1e2e" +foreground = "#cdd6f4" +primary = "#cba6f7" +secondary = "#89b4fa" +accent = "#f38ba8" +muted = "#6c7086" +""" + +# --- Logging Setup --- + +def setup_logging(level): + """Sets up the logging configuration based on the provided level.""" + log_level = getattr(logging, level.upper(), logging.INFO) + logging.basicConfig( + level=log_level, + format='%(asctime)s - %(levelname)s - %(message)s' + ) + +# --- Helper Functions --- + +def get_config_dir(): + """Returns the XDG config directory for the application, creating it if necessary.""" + xdg_config_home = os.environ.get("XDG_CONFIG_HOME") + config_dir = Path(xdg_config_home) / APP_NAME if xdg_config_home else Path.home() / ".config" / APP_NAME + + # Create the directory if it doesn't exist + if not config_dir.exists(): + try: + config_dir.mkdir(parents=True) + logging.info(f"Created configuration directory at {config_dir}") + except Exception as e: + logging.error(f"Failed to create configuration directory: {e}") + + return config_dir + +def create_default_theme_file(config_dir): + """Creates a default theme file if one doesn't exist.""" + theme_file_path = config_dir / f"{DEFAULT_THEME_NAME}.toml" + if not theme_file_path.exists(): + try: + with open(theme_file_path, "w") as f: + f.write(DEFAULT_THEME_CONTENT) + logging.info(f"Created default theme file '{DEFAULT_THEME_NAME}.toml'") + except Exception as e: + logging.error(f"Failed to create default theme file: {e}") + +def hex_to_rgb(hex_color): + """Converts a hex color string to an RGB tuple.""" + hex_color = hex_color.lstrip('#') + return tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4)) + +def load_palette(theme_name, variant_name): + """ + Loads a color palette from a TOML file based on its theme name and variant. + """ + config_dir = get_config_dir() + + # Iterate through all TOML files to find a matching theme and variant + for theme_file in config_dir.glob("*.toml"): + try: + with open(theme_file, 'rb') as f: + palette_data = pytoml.load(f) + + # Check for name and variant match + data = palette_data.get('data', {}) + if data.get('name') == theme_name and data.get('variant') == variant_name: + if "colors" not in palette_data: + logging.fatal(f"Invalid theme file: '{theme_file.name}' is missing the [colors] table.") + sys.exit(1) + + logging.info(f"Loaded theme '{theme_name}' variant '{variant_name}' from '{theme_file.name}'") + + # Filter and convert colors from the [colors] table + hex_colors = [v for k, v in palette_data['colors'].items() if isinstance(v, str)] + return [hex_to_rgb(h) for h in hex_colors] + + except Exception as e: + logging.debug(f"Could not parse theme file {theme_file.name}: {e}") + continue + + # If loop completes without finding a match + logging.fatal(f"Color scheme '{theme_name}:{variant_name}' not found.") + sys.exit(1) + +def list_themes(): + """Lists available theme files, grouping them by name and showing variants.""" + config_dir = get_config_dir() + if not config_dir.is_dir(): + logging.info(f"Theme directory not found at {config_dir}") + return + + # Dictionary to store themes, grouped by name + themes = {} + + for theme_file in sorted(config_dir.glob("*.toml")): + file_name = theme_file.stem + try: + with open(theme_file, 'rb') as f: + data = pytoml.load(f) + + display_name = data.get('data', {}).get('name', file_name) + variant = data.get('data', {}).get('variant', 'default') + + # Generate the color blocks + color_blocks = "" + colors = data.get('colors', {}) + for hex_color in colors.values(): + if isinstance(hex_color, str) and hex_color.startswith('#'): + rgb = hex_to_rgb(hex_color) + color_blocks += f"\033[48;2;{rgb[0]};{rgb[1]};{rgb[2]}m \033[0m" + + if display_name not in themes: + themes[display_name] = [] + themes[display_name].append({ + 'variant': variant, + 'file_name': f"{file_name}.toml", + 'color_blocks': color_blocks + }) + + except Exception as e: + logging.debug(f"Error parsing {theme_file}: {e}") + if 'unknown' not in themes: + themes['unknown'] = [] + themes['unknown'].append({ + 'variant': 'N/A', + 'file_name': f"{file_name}.toml", + 'color_blocks': '' + }) + + print("Available color schemes:") + for display_name in sorted(themes.keys()): + print(f"- {display_name}") + for variant_info in themes[display_name]: + print(f" - {variant_info['color_blocks']} {variant_info['variant']} ({variant_info['file_name']})") + +def clamp(value, min_val=0, max_val=255): + """Clamps a value within a specified range.""" + return max(min_val, min(max_val, value)) + +def adjust_brightness(r, g, b, brightness): + """ + Adjusts the brightness of an RGB color. + Brightness is a value from -100 (darken) to 100 (lighten). + """ + adjustment = (brightness / 100) * 255 + return ( + clamp(r + adjustment), + clamp(g + adjustment), + clamp(b + adjustment) + ) + +def rgb_to_hsl(r, g, b): + r /= 255.0 + g /= 255.0 + b /= 255.0 + + max_val = max(r, g, b) + min_val = min(r, g, b) + h, s, l = 0, 0, (max_val + min_val) / 2.0 + + if max_val != min_val: + diff = max_val - min_val + s = diff / (2.0 - max_val - min_val) if l > 0.5 else diff / (max_val + min_val) + if max_val == r: + h = (g - b) / diff + (6 if g < b else 0) + elif max_val == g: + h = (b - r) / diff + 2 + elif max_val == b: + h = (r - g) / diff + 4 + h /= 6.0 + + return [h * 360, s, l] + +def hsl_to_rgb(h, s, l): + h /= 360.0 + + def hue_to_rgb(p, q, t): + if t < 0: t += 1 + if t > 1: t -= 1 + if t < 1/6: return p + (q - p) * 6 * t + if t < 1/2: return q + if t < 2/3: return p + (q - p) * (2/3 - t) * 6 + return p + + if s == 0: + r = g = b = l + else: + q = l * (1 + s) if l < 0.5 else l + s - l * s + p = 2 * l - q + r = hue_to_rgb(p, q, h + 1/3) + g = hue_to_rgb(p, q, h) + b = hue_to_rgb(p, q, h - 1/3) + + return [int(r * 255), int(g * 255), int(b * 255)] + +def adjust_saturation(r, g, b, saturation): + """Adjusts the saturation of an RGB color.""" + h, s, l = rgb_to_hsl(r, g, b) + new_s = max(0, min(1, s * saturation)) + return hsl_to_rgb(h, new_s, l) + + +# --- Core Colorization Logic (Translated from imageColorizer.ts) --- + +def colorize_image(image_path, selected_colors, brightness_adjustment=0, saturation_adjustment=1.0): + """ + Colorizes an image using the provided colors based on their declared order, + with options for brightness and saturation adjustment. + """ + logging.info(f"Colorizing image '{image_path}' with {len(selected_colors)} colors...") + + try: + img = Image.open(image_path).convert('RGB') + pixels = np.array(img) + except FileNotFoundError: + logging.fatal(f"Input image not found: {image_path}") + sys.exit(1) + except Exception as e: + logging.fatal(f"Error opening image: {e}") + sys.exit(1) + + # Convert image and palette to Lab color space + image_lab = rgb2lab(pixels / 255.0) + palette_lab = rgb2lab(np.array(selected_colors) / 255.0) + + new_pixels_lab = np.zeros_like(image_lab) + + for i in range(image_lab.shape[0]): + for j in range(image_lab.shape[1]): + pixel_lab = image_lab[i, j] + original_L = pixel_lab[0] + + # Map the original lightness (0-100) to an index in the palette. + # This ensures the original order of colors is used. + palette_index = (original_L / 100) * (len(palette_lab) - 1) + lower_index = int(palette_index) + upper_index = min(lower_index + 1, len(palette_lab) - 1) + + # Get the colors to interpolate between + lower_color = palette_lab[lower_index] + upper_color = palette_lab[upper_index] + + amount = palette_index - lower_index + + # Interpolate the color in Lab space + interpolated_L = original_L + interpolated_a = lower_color[1] + (upper_color[1] - lower_color[1]) * amount + interpolated_b = lower_color[2] + (upper_color[2] - lower_color[2]) * amount + + new_pixels_lab[i, j] = [interpolated_L, interpolated_a, interpolated_b] + + # Convert back to RGB + new_pixels_rgb = (lab2rgb(new_pixels_lab) * 255).astype(np.uint8) + + # Apply saturation and brightness adjustments + for i in range(new_pixels_rgb.shape[0]): + for j in range(new_pixels_rgb.shape[1]): + r, g, b = new_pixels_rgb[i, j] + + # Apply saturation adjustment first + if saturation_adjustment != 1.0: + r, g, b = adjust_saturation(r, g, b, saturation_adjustment) + + # Apply brightness adjustment second + if brightness_adjustment != 0: + r, g, b = adjust_brightness(r, g, b, brightness_adjustment) + + new_pixels_rgb[i, j] = [r, g, b] + + return Image.fromarray(new_pixels_rgb) + +# --- Main Execution --- + +def main(): + parser = argparse.ArgumentParser( + description="A command-line utility to colorize wallpapers with color palettes." + ) + + parser.add_argument("-i", "--input", help="Path to the input image file.", required=False) + parser.add_argument("-t", "--theme", help="The theme name and variant to use, e.g., 'Catppuccin:dark'.", required=False) + parser.add_argument("-s", "--saturation", type=float, default=1.0, help="Adjust saturation. 0.0 is desaturated, 1.0 is default, >1.0 is more saturated.") + parser.add_argument("-d", "--darken", type=float, default=0, help="Darken (-100) or lighten (100) the image.") + parser.add_argument("-l", "--list", action="store_true", help="Lists available color schemes.") + parser.add_argument("output", nargs="?", help="Path for the output image file.") + + log_group = parser.add_mutually_exclusive_group() + log_group.add_argument("-L", "--log-level", choices=LOG_LEVELS, default="INFO", help="Set the logging level.") + log_group.add_argument("-v", "--verbose", action="store_true", help="Alias for -L DEBUG.") + + args = parser.parse_args() + + # Handle logging level first + log_level = "DEBUG" if args.verbose else args.log_level + setup_logging(log_level) + + # Prepare configuration directory and default theme + config_dir = get_config_dir() + create_default_theme_file(config_dir) + + # Handle list command + if args.list: + list_themes() + sys.exit(0) + + # Validate required arguments for colorization + if not all([args.input, args.theme, args.output]): + parser.error("The -i, -t, and output arguments are required unless -l is used.") + + # Parse theme name and variant + if ':' not in args.theme: + logging.fatal("Theme selection must be in the format 'name:variant'.") + sys.exit(1) + + theme_name, variant_name = args.theme.split(':', 1) + + # Main colorization process + selected_colors_rgb = load_palette(theme_name, variant_name) + output_image = colorize_image(args.input, selected_colors_rgb, args.darken, args.saturation) + + try: + output_image.save(args.output) + logging.info(f"Successfully saved colorized image to '{args.output}'") + except Exception as e: + logging.fatal(f"Error saving output image: {e}") + sys.exit(1) + +if __name__ == "__main__": + main() diff --git a/.set-wallpaper.sh b/.set-wallpaper.sh index b41f26e..b4fc240 100755 --- a/.set-wallpaper.sh +++ b/.set-wallpaper.sh @@ -7,6 +7,7 @@ WALLPAPER_HOME=$(realpath "${WALLPAPER_HOME/#~/$HOME}") selected_file=$( ( while IFS= read -r file; do +<<<<<<< HEAD # Pass the image path as an icon printf "%s\0icon\x1f%s\n" "$(basename "$file")" "$file" done < <(find "$WALLPAPER_HOME" -maxdepth 1 -name '*.jpg') @@ -34,3 +35,25 @@ cp "$selected" "$WALLPAPER_HOME/current/current.jpg" export WALLPAPER=$(cat "$WALLPAPER_HOME/current/selected") hyprctl hyprpaper wallpaper ", $WALLPAPER" matugen -t scheme-content image "$WALLPAPER_HOME/current/current.jpg" +======= + echo "$(basename "$file")" + done < <(find $WALLPAPER_HOME -maxdepth 1 -name '*.jpg') + ) | sort | rofi -dmenu -i -p "Wallpapers" +) + +if [ -z $selected_file ]; then + exit 1 +fi + +if [ ! -d $WALLPAPER_HOME/current ]; then + mkdir $WALLPAPER_HOME/current/ +fi + +selected="$WALLPAPER_HOME/$selected_file" +echo $selected > $WALLPAPER_HOME/current/selected +magick $selected -scale 10% -blur 0x2.5 -resize 1000% $WALLPAPER_HOME/current/blurred.jpg +cp $selected $WALLPAPER_HOME/current/current.jpg +export WALLPAPER=$(cat $WALLPAPER_HOME/current/selected) +hyprctl hyprpaper wallpaper ", $WALLPAPER" +matugen -t scheme-content image $WALLPAPER_HOME/current/current.jpg +>>>>>>> 912aac4 (chore: add thinkpad wallpapers) diff --git a/Audi_RS3-Sportback.jpg b/Audi_RS3-Sportback.jpg new file mode 100644 index 0000000..36c04fd Binary files /dev/null and b/Audi_RS3-Sportback.jpg differ diff --git a/Audi_RS3-Sportback_cyberdream.jpg b/Audi_RS3-Sportback_cyberdream.jpg new file mode 100644 index 0000000..564b279 Binary files /dev/null and b/Audi_RS3-Sportback_cyberdream.jpg differ diff --git a/astonmartin_vulcan-amr-pro.jpg b/astonmartin_vulcan-amr-pro.jpg new file mode 100644 index 0000000..fd8c743 Binary files /dev/null and b/astonmartin_vulcan-amr-pro.jpg differ diff --git a/audi_rs3-2021.jpg b/audi_rs3-2021.jpg new file mode 100644 index 0000000..43f4fd3 Binary files /dev/null and b/audi_rs3-2021.jpg differ diff --git a/audi_rs3-2021_cyberdream.jpg b/audi_rs3-2021_cyberdream.jpg new file mode 100644 index 0000000..1a65675 Binary files /dev/null and b/audi_rs3-2021_cyberdream.jpg differ diff --git a/camaro_zl1-2020.jpg b/camaro_zl1-2020.jpg new file mode 100644 index 0000000..9fb3817 Binary files /dev/null and b/camaro_zl1-2020.jpg differ diff --git a/camaro_zl1-2020_cyberdream.jpg b/camaro_zl1-2020_cyberdream.jpg new file mode 100644 index 0000000..4da921e Binary files /dev/null and b/camaro_zl1-2020_cyberdream.jpg differ diff --git a/chernobyl.jpg b/chernobyl.jpg new file mode 100644 index 0000000..2f7a83e Binary files /dev/null and b/chernobyl.jpg differ diff --git a/chernobyl_cyberdream.jpg b/chernobyl_cyberdream.jpg new file mode 100644 index 0000000..40bc55c Binary files /dev/null and b/chernobyl_cyberdream.jpg differ diff --git a/cupra_leon-2020.jpg b/cupra_leon-2020.jpg new file mode 100644 index 0000000..1aadd39 Binary files /dev/null and b/cupra_leon-2020.jpg differ diff --git a/cupra_leon-2020_cyberdream.jpg b/cupra_leon-2020_cyberdream.jpg new file mode 100644 index 0000000..7286eaf Binary files /dev/null and b/cupra_leon-2020_cyberdream.jpg differ diff --git a/current/blurred.jpg b/current/blurred.jpg deleted file mode 100644 index 4a7381b..0000000 Binary files a/current/blurred.jpg and /dev/null differ diff --git a/current/current.jpg b/current/current.jpg deleted file mode 100644 index e9444c6..0000000 Binary files a/current/current.jpg and /dev/null differ diff --git a/current/selected b/current/selected deleted file mode 100644 index 840cf73..0000000 --- a/current/selected +++ /dev/null @@ -1 +0,0 @@ -/home/jan/wallpapers/r26.jpg diff --git a/f2004.jpg b/f2004.jpg new file mode 100644 index 0000000..550740d Binary files /dev/null and b/f2004.jpg differ diff --git a/f2004_cyberdream.jpg b/f2004_cyberdream.jpg new file mode 100644 index 0000000..543f13a Binary files /dev/null and b/f2004_cyberdream.jpg differ diff --git a/mclaren_600-spider_2020.jpg b/mclaren_600-spider_2020.jpg new file mode 100644 index 0000000..7c86177 Binary files /dev/null and b/mclaren_600-spider_2020.jpg differ diff --git a/mclaren_600-spider_2020_cyberdream.jpg b/mclaren_600-spider_2020_cyberdream.jpg new file mode 100644 index 0000000..37e468e Binary files /dev/null and b/mclaren_600-spider_2020_cyberdream.jpg differ diff --git a/originals/Audi_RS3-Sportback.jpg b/originals/Audi_RS3-Sportback.jpg new file mode 100644 index 0000000..493e088 Binary files /dev/null and b/originals/Audi_RS3-Sportback.jpg differ diff --git a/originals/Audi_RS3-Sportback_cyberdream.jpg b/originals/Audi_RS3-Sportback_cyberdream.jpg new file mode 100644 index 0000000..564b279 Binary files /dev/null and b/originals/Audi_RS3-Sportback_cyberdream.jpg differ diff --git a/originals/astonmartin_vulcan-amr-pro.jpg b/originals/astonmartin_vulcan-amr-pro.jpg new file mode 100644 index 0000000..b09765e Binary files /dev/null and b/originals/astonmartin_vulcan-amr-pro.jpg differ diff --git a/originals/audi_rs3-2021.jpg b/originals/audi_rs3-2021.jpg new file mode 100644 index 0000000..f6162cc Binary files /dev/null and b/originals/audi_rs3-2021.jpg differ diff --git a/originals/camaro_zl1-2020.jpg b/originals/camaro_zl1-2020.jpg new file mode 100644 index 0000000..5ff5c91 Binary files /dev/null and b/originals/camaro_zl1-2020.jpg differ diff --git a/originals/cupra_leon-2020.jpg b/originals/cupra_leon-2020.jpg new file mode 100644 index 0000000..26d5278 Binary files /dev/null and b/originals/cupra_leon-2020.jpg differ diff --git a/originals/f2004.jpg b/originals/f2004.jpg new file mode 100644 index 0000000..0134fe7 Binary files /dev/null and b/originals/f2004.jpg differ diff --git a/originals/f2004_catppuccin.jpg b/originals/f2004_catppuccin.jpg new file mode 100644 index 0000000..3af25a9 Binary files /dev/null and b/originals/f2004_catppuccin.jpg differ diff --git a/originals/f2004_cyberdream.jpg b/originals/f2004_cyberdream.jpg new file mode 100644 index 0000000..72b9af4 Binary files /dev/null and b/originals/f2004_cyberdream.jpg differ diff --git a/originals/mclaren_600-spider_2020.jpg.jpg b/originals/mclaren_600-spider_2020.jpg.jpg new file mode 100644 index 0000000..23a22cc Binary files /dev/null and b/originals/mclaren_600-spider_2020.jpg.jpg differ diff --git a/originals/porsche_911-gt3rs.jpg b/originals/porsche_911-gt3rs.jpg new file mode 100644 index 0000000..fdf7086 Binary files /dev/null and b/originals/porsche_911-gt3rs.jpg differ diff --git a/originals/r26.jpg b/originals/r26.jpg new file mode 100644 index 0000000..c770608 Binary files /dev/null and b/originals/r26.jpg differ diff --git a/originals/rb22.jpg b/originals/rb22.jpg new file mode 100644 index 0000000..70134e2 Binary files /dev/null and b/originals/rb22.jpg differ diff --git a/originals/w11.jpg b/originals/w11.jpg new file mode 100644 index 0000000..12e60c7 Binary files /dev/null and b/originals/w11.jpg differ diff --git a/originals/windows_xp.jpg b/originals/windows_xp.jpg new file mode 100644 index 0000000..7ac1bd0 Binary files /dev/null and b/originals/windows_xp.jpg differ diff --git a/porsche_911-gt3rs.jpg b/porsche_911-gt3rs.jpg new file mode 100644 index 0000000..168770b Binary files /dev/null and b/porsche_911-gt3rs.jpg differ diff --git a/porsche_911-gt3rs_cyberdream.jpg b/porsche_911-gt3rs_cyberdream.jpg new file mode 100644 index 0000000..5731e85 Binary files /dev/null and b/porsche_911-gt3rs_cyberdream.jpg differ diff --git a/rb19.jpg b/rb19.jpg new file mode 100644 index 0000000..bba18bd Binary files /dev/null and b/rb19.jpg differ diff --git a/rb19_cyberdream.jpg b/rb19_cyberdream.jpg new file mode 100644 index 0000000..805230e Binary files /dev/null and b/rb19_cyberdream.jpg differ diff --git a/w11.jpg b/w11.jpg new file mode 100644 index 0000000..965726e Binary files /dev/null and b/w11.jpg differ diff --git a/w11_cyberdream.jpg b/w11_cyberdream.jpg new file mode 100644 index 0000000..3771675 Binary files /dev/null and b/w11_cyberdream.jpg differ diff --git a/windows_xp-cyberdream.jpg b/windows_xp-cyberdream.jpg new file mode 100644 index 0000000..7b9cddd Binary files /dev/null and b/windows_xp-cyberdream.jpg differ diff --git a/windows_xp.jpg b/windows_xp.jpg new file mode 100644 index 0000000..bf80850 Binary files /dev/null and b/windows_xp.jpg differ