summaryrefslogtreecommitdiff
path: root/pywal
diff options
context:
space:
mode:
authorDylan Araps <dylan.araps@gmail.com>2018-04-01 09:34:34 +1000
committerDylan Araps <dylan.araps@gmail.com>2018-04-01 09:34:34 +1000
commit400e7d0c42af803dd5ac4bd5bedc6a65f7298eb4 (patch)
treee0175b631d42a54cf5230a01cf965e264a6cd8a8 /pywal
parent40454ff0c642b13b9cfcd114dfeb1c71829227db (diff)
parente25bc9e2d895f3bbf157cceaf7077c463369ad59 (diff)
general: rebase
Diffstat (limited to 'pywal')
-rw-r--r--pywal/__main__.py19
-rw-r--r--pywal/backends/__init__.py10
-rw-r--r--pywal/backends/colorthief.py64
-rw-r--r--pywal/backends/colorz.py36
-rw-r--r--pywal/backends/haishoku.py36
-rw-r--r--pywal/backends/schemer2.py34
-rw-r--r--pywal/backends/wal.py87
-rw-r--r--pywal/colors.py177
-rw-r--r--pywal/reload.py8
-rw-r--r--pywal/sequences.py7
-rw-r--r--pywal/settings.py1
-rw-r--r--pywal/util.py5
12 files changed, 372 insertions, 112 deletions
diff --git a/pywal/__main__.py b/pywal/__main__.py
index 2447b6b..2857ae3 100644
--- a/pywal/__main__.py
+++ b/pywal/__main__.py
@@ -37,6 +37,10 @@ def get_args(args):
arg.add_argument("-b", metavar="background",
help="Custom background color to use.")
+ arg.add_argument("--backend", metavar="backend",
+ help="Which color backend to use.",
+ const="list_backends", type=str, nargs="?", default="wal")
+
arg.add_argument("-c", action="store_true",
help="Delete all cached colorschemes.")
@@ -73,8 +77,8 @@ def get_args(args):
arg.add_argument("-s", action="store_true",
help="Skip changing colors in terminals.")
- arg.add_argument("-t", action="store_false",
- help="Deprecated: Does nothing and is no longer needed.")
+ arg.add_argument("-t", action="store_true",
+ help="Skip changing colors in tty.")
arg.add_argument("-v", action="store_true",
help="Print \"wal\" version.")
@@ -111,6 +115,10 @@ def process_args(args):
print("Extra: 'random (select a random theme)'")
sys.exit(0)
+ if args.backend == "list_backends":
+ print("Available backends:", colors.list_backends())
+ sys.exit(0)
+
if args.q:
sys.stdout = sys.stderr = open(os.devnull, "w")
@@ -129,7 +137,7 @@ def process_args(args):
if args.i:
image_file = image.get(args.i)
- colors_plain = colors.get(image_file, light=args.l)
+ colors_plain = colors.get(image_file, args.l, args.backend)
if args.f:
colors_plain = theme.file(args.f)
@@ -146,13 +154,12 @@ def process_args(args):
if not args.n:
wallpaper.change(colors_plain["wallpaper"])
- if not args.s:
- sequences.send(colors_plain)
+ sequences.send(colors_plain, to_send=not args.s)
export.every(colors_plain)
if not args.e:
- reload.env()
+ reload.env(tty_reload=not args.t)
if args.o:
util.disown([args.o])
diff --git a/pywal/backends/__init__.py b/pywal/backends/__init__.py
new file mode 100644
index 0000000..9a116e8
--- /dev/null
+++ b/pywal/backends/__init__.py
@@ -0,0 +1,10 @@
+r"""
+Hh ____
+HP "HHF:. `._ :.,-'"" "-.
+F F" :::..'"" "-. `.
+F , \ \ "BACKENDS"
+F j\ / ; `. - sorry
+| j `. ` A \
+| | ;_ . 8 \
+J F\_,'| "`-----.\ j `. \
+"""
diff --git a/pywal/backends/colorthief.py b/pywal/backends/colorthief.py
new file mode 100644
index 0000000..180af5f
--- /dev/null
+++ b/pywal/backends/colorthief.py
@@ -0,0 +1,64 @@
+"""
+Generate a colorscheme using ColorThief.
+"""
+import sys
+
+try:
+ from colorthief import ColorThief
+
+except ImportError:
+ print("error: ColorThief wasn't found on your system.",
+ "Try another backend. (wal --backend)")
+ sys.exit(1)
+
+from .. import util
+
+
+def gen_colors(img):
+ """Loop until 16 colors are generated."""
+ color_cmd = ColorThief(img).get_palette
+
+ for i in range(0, 10, 1):
+ raw_colors = color_cmd(color_count=8 + i)
+
+ if len(raw_colors) >= 8:
+ break
+
+ elif i == 19:
+ print("colors: ColorThief couldn't generate a suitable palette",
+ "for the image. Exiting...")
+ sys.exit(1)
+
+ else:
+ print("colors: ColorThief couldn't create a suitable palette, "
+ "trying a larger palette size", 8 + i)
+
+ return [util.rgb_to_hex(color) for color in raw_colors]
+
+
+def adjust(cols, light):
+ """Create palette."""
+ cols.sort(key=util.rgb_to_yiq)
+ raw_colors = [*cols, *cols]
+
+ if light:
+ raw_colors[0] = util.lighten_color(cols[0], 0.90)
+ raw_colors[7] = util.darken_color(cols[0], 0.75)
+
+ else:
+ for color in raw_colors:
+ color = util.lighten_color(color, 0.40)
+
+ raw_colors[0] = util.darken_color(cols[0], 0.80)
+ raw_colors[7] = util.lighten_color(cols[0], 0.60)
+
+ raw_colors[8] = util.lighten_color(cols[0], 0.20)
+ raw_colors[15] = raw_colors[7]
+
+ return raw_colors
+
+
+def get(img, light=False):
+ """Get colorscheme."""
+ cols = gen_colors(img)
+ return adjust(cols, light)
diff --git a/pywal/backends/colorz.py b/pywal/backends/colorz.py
new file mode 100644
index 0000000..0c5148d
--- /dev/null
+++ b/pywal/backends/colorz.py
@@ -0,0 +1,36 @@
+"""
+Generate a colorscheme using Colorz.
+"""
+import shutil
+import subprocess
+import sys
+
+from .. import colors
+from .. import util
+
+
+def gen_colors(img):
+ """Generate a colorscheme using Colorz."""
+ cmd = ["colorz", "-n", "6", "--bold", "0", "--no-preview"]
+ return subprocess.check_output([*cmd, img]).splitlines()
+
+
+def adjust(cols, light):
+ """Create palette."""
+ bg = util.blend_color("#555555", cols[1])
+
+ raw_colors = [bg, *cols, "#FFFFFF",
+ "#333333", *cols, "#FFFFFF"]
+
+ return colors.generic_adjust(raw_colors, light)
+
+
+def get(img, light=False):
+ """Get colorscheme."""
+ if not shutil.which("colorz"):
+ print("error: Colorz wasn't found on your system.",
+ "Try another backend. (wal --backend)")
+ sys.exit(1)
+
+ cols = [col.decode('UTF-8').split()[0] for col in gen_colors(img)]
+ return adjust(cols, light)
diff --git a/pywal/backends/haishoku.py b/pywal/backends/haishoku.py
new file mode 100644
index 0000000..413c9d7
--- /dev/null
+++ b/pywal/backends/haishoku.py
@@ -0,0 +1,36 @@
+"""
+Generate a colorscheme using Haishoku.
+"""
+import sys
+
+try:
+ from haishoku.haishoku import Haishoku
+
+except ImportError:
+ print("error: Haishoku wasn't found on your system.",
+ "Try another backend. (wal --backend)")
+ sys.exit(1)
+
+from .. import colors
+from .. import util
+
+
+def gen_colors(img):
+ """Generate a colorscheme using Colorz."""
+ palette = Haishoku.getPalette(img)
+ return [util.rgb_to_hex(col[1]) for col in palette]
+
+
+def adjust(cols, light):
+ """Create palette."""
+ cols.sort(key=util.rgb_to_yiq)
+ raw_colors = [*cols, *cols]
+ raw_colors[0] = util.lighten_color(cols[0], 0.40)
+
+ return colors.generic_adjust(raw_colors, light)
+
+
+def get(img, light=False):
+ """Get colorscheme."""
+ cols = gen_colors(img)
+ return adjust(cols, light)
diff --git a/pywal/backends/schemer2.py b/pywal/backends/schemer2.py
new file mode 100644
index 0000000..87873ec
--- /dev/null
+++ b/pywal/backends/schemer2.py
@@ -0,0 +1,34 @@
+"""
+Generate a colorscheme using Schemer2.
+"""
+import shutil
+import subprocess
+import sys
+
+from .. import colors
+from .. import util
+
+
+def gen_colors(img):
+ """Generate a colorscheme using Colorz."""
+ cmd = ["schemer2", "-format", "img::colors", "-minBright", "75", "-in"]
+ return subprocess.check_output([*cmd, img]).splitlines()
+
+
+def adjust(cols, light):
+ """Create palette."""
+ cols.sort(key=util.rgb_to_yiq)
+ raw_colors = [*cols[8:], *cols[8:]]
+
+ return colors.generic_adjust(raw_colors, light)
+
+
+def get(img, light=False):
+ """Get colorscheme."""
+ if not shutil.which("schemer2"):
+ print("error: Schemer2 wasn't found on your system.",
+ "Try another backend. (wal --backend)")
+ sys.exit(1)
+
+ cols = [col.decode('UTF-8') for col in gen_colors(img)]
+ return adjust(cols, light)
diff --git a/pywal/backends/wal.py b/pywal/backends/wal.py
new file mode 100644
index 0000000..678c66c
--- /dev/null
+++ b/pywal/backends/wal.py
@@ -0,0 +1,87 @@
+"""
+Generate a colorscheme using imagemagick.
+"""
+import re
+import shutil
+import subprocess
+import sys
+
+from .. import util
+
+
+def imagemagick(color_count, img, magick_command):
+ """Call Imagemagick to generate a scheme."""
+ flags = ["-resize", "25%", "-colors", str(color_count),
+ "-unique-colors", "txt:-"]
+ img += "[0]"
+
+ return subprocess.check_output([*magick_command, img, *flags]).splitlines()
+
+
+def has_im():
+ """Check to see if the user has im installed."""
+ if shutil.which("magick"):
+ return ["magick", "convert"]
+
+ elif shutil.which("convert"):
+ return ["convert"]
+
+ print("error: ImageMagick wasn't found on your system.",
+ "Try another backend. (wal --backend)")
+ sys.exit(1)
+
+
+def gen_colors(img):
+ """Format the output from imagemagick into a list
+ of hex colors."""
+ magick_command = has_im()
+
+ for i in range(0, 20, 1):
+ raw_colors = imagemagick(16 + i, img, magick_command)
+
+ if len(raw_colors) > 16:
+ break
+
+ elif i == 19:
+ print("colors: Imagemagick couldn't generate a suitable palette",
+ "for the image. Exiting...")
+ sys.exit(1)
+
+ else:
+ print("colors: Imagemagick couldn't generate a suitable palette, "
+ "trying a larger palette size", 16 + i)
+
+ return [re.search("#.{6}", str(col)).group(0) for col in raw_colors[1:]]
+
+
+def adjust(colors, light):
+ """Adjust the generated colors and store them in a dict that
+ we will later save in json format."""
+ raw_colors = colors[:1] + colors[8:16] + colors[8:-1]
+
+ # Manually adjust colors.
+ if light:
+ for color in raw_colors:
+ color = util.saturate_color(color, 0.5)
+
+ raw_colors[0] = util.lighten_color(colors[-1], 0.85)
+ raw_colors[7] = colors[0]
+ raw_colors[8] = util.darken_color(colors[-1], 0.4)
+ raw_colors[15] = colors[0]
+
+ else:
+ # Darken the background color slightly.
+ if raw_colors[0][1] != "0":
+ raw_colors[0] = util.darken_color(raw_colors[0], 0.25)
+
+ raw_colors[7] = util.blend_color(raw_colors[7], "#EEEEEE")
+ raw_colors[8] = util.darken_color(raw_colors[7], 0.30)
+ raw_colors[15] = util.blend_color(raw_colors[15], "#EEEEEE")
+
+ return raw_colors
+
+
+def get(img, light=False):
+ """Get colorscheme."""
+ colors = gen_colors(img)
+ return adjust(colors, light)
diff --git a/pywal/colors.py b/pywal/colors.py
index 90f7ba2..33b68d5 100644
--- a/pywal/colors.py
+++ b/pywal/colors.py
@@ -1,116 +1,90 @@
"""
-Generate a colorscheme using imagemagick.
+Generate a palette using various backends.
"""
import os
import re
-import shutil
-import subprocess
import sys
from . import theme
-
-from .settings import CACHE_DIR, COLOR_COUNT, __cache_version__
from . import util
-
-
-def imagemagick(color_count, img, magick_command):
- """Call Imagemagick to generate a scheme."""
- flags = ["-resize", "25%", "-colors", str(color_count),
- "-unique-colors", "txt:-"]
- img += "[0]"
-
- return subprocess.check_output([*magick_command, img, *flags]).splitlines()
-
-
-def has_im():
- """Check to see if the user has im installed."""
- if shutil.which("magick"):
- return ["magick", "convert"]
-
- elif shutil.which("convert"):
- return ["convert"]
-
- print("error: imagemagick not found, exiting...\n"
- "error: wal requires imagemagick to function.")
- sys.exit(1)
-
-
-def gen_colors(img, color_count):
- """Format the output from imagemagick into a list
- of hex colors."""
- magick_command = has_im()
-
- for i in range(0, 20, 1):
- raw_colors = imagemagick(color_count + i, img, magick_command)
-
- if len(raw_colors) > 16:
- break
-
- elif i == 19:
- print("colors: Imagemagick couldn't generate a suitable scheme",
- "for the image. Exiting...")
- sys.exit(1)
-
- else:
- print("colors: Imagemagick couldn't generate a %s color palette, "
- "trying a larger palette size %s."
- % (color_count, color_count + i))
-
- return [re.search("#.{6}", str(col)).group(0) for col in raw_colors[1:]]
-
-
-def create_palette(img, colors, light):
- """Sort the generated colors and store them in a dict that
- we will later save in json format."""
- raw_colors = colors[:1] + colors[8:16] + colors[8:-1]
-
- if light:
- # Manually adjust colors.
- raw_colors[7] = raw_colors[0]
- raw_colors[0] = util.lighten_color(raw_colors[15], 0.85)
- raw_colors[15] = raw_colors[7]
- raw_colors[8] = util.lighten_color(raw_colors[7], 0.25)
-
- else:
- # Darken the background color slightly.
- if raw_colors[0][1] != "0":
- raw_colors[0] = util.darken_color(raw_colors[0], 0.25)
-
- # Manually adjust colors.
- raw_colors[7] = util.blend_color(raw_colors[7], "#EEEEEE")
- raw_colors[8] = util.darken_color(raw_colors[7], 0.30)
- raw_colors[15] = util.blend_color(raw_colors[15], "#EEEEEE")
-
- colors = {"wallpaper": img, "alpha": util.Color.alpha_num,
- "special": {}, "colors": {}}
- colors["special"]["background"] = raw_colors[0]
- colors["special"]["foreground"] = raw_colors[15]
- colors["special"]["cursor"] = raw_colors[15]
-
+from .settings import CACHE_DIR, MODULE_DIR, __cache_version__
+
+
+def list_backends():
+ """List color backends."""
+ return [b.name.replace(".py", "") for b in
+ os.scandir(os.path.join(MODULE_DIR, "backends"))
+ if "__" not in b.name]
+
+
+def colors_to_dict(colors, img):
+ """Convert list of colors to pywal format."""
+ return {
+ "wallpaper": img,
+ "alpha": util.Color.alpha_num,
+
+ "special": {
+ "background": colors[0],
+ "foreground": colors[15],
+ "cursor": colors[1]
+ },
+
+ "colors": {
+ "color0": colors[0],
+ "color1": colors[1],
+ "color2": colors[2],
+ "color3": colors[3],
+ "color4": colors[4],
+ "color5": colors[5],
+ "color6": colors[6],
+ "color7": colors[7],
+ "color8": colors[8],
+ "color9": colors[9],
+ "color10": colors[10],
+ "color11": colors[11],
+ "color12": colors[12],
+ "color13": colors[13],
+ "color14": colors[14],
+ "color15": colors[15]
+ }
+ }
+
+
+def generic_adjust(colors, light):
+ """Generic color adjustment for themers."""
if light:
- for i, color in enumerate(raw_colors):
- colors["colors"]["color%s" % i] = util.saturate_color(color, 0.5)
+ for color in colors:
+ color = util.saturate_color(color, 0.50)
+ color = util.darken_color(color, 0.4)
- colors["colors"]["color0"] = raw_colors[0]
- colors["colors"]["color7"] = raw_colors[15]
- colors["colors"]["color8"] = util.darken_color(raw_colors[0], 0.5)
- colors["colors"]["color15"] = raw_colors[15]
+ colors[0] = util.lighten_color(colors[0], 0.9)
+ colors[7] = util.darken_color(colors[0], 0.75)
+ colors[8] = util.darken_color(colors[0], 0.25)
+ colors[15] = colors[7]
else:
- for i, color in enumerate(raw_colors):
- colors["colors"]["color%s" % i] = color
+ colors[0] = util.darken_color(colors[0], 0.75)
+ colors[7] = util.lighten_color(colors[0], 0.75)
+ colors[8] = util.lighten_color(colors[0], 0.25)
+ colors[15] = colors[7]
return colors
-def get(img, cache_dir=CACHE_DIR,
- color_count=COLOR_COUNT, light=False):
- """Get the colorscheme."""
- # home_dylan_img_jpg_1.2.2.json
+def cache_fname(img, backend, light, cache_dir):
+ """Create the cache file name."""
color_type = "light" if light else "dark"
- cache_file = re.sub("[/|\\|.]", "_", img)
- cache_file = os.path.join(cache_dir, "schemes", "%s_%s_%s.json"
- % (cache_file, color_type, __cache_version__))
+ file_name = re.sub("[/|\\|.]", "_", img)
+
+ file_parts = [file_name, color_type, backend, __cache_version__]
+ return [cache_dir, "schemes", "%s_%s_%s_%s.json" % (*file_parts,)]
+
+
+def get(img, light=False, backend="wal", cache_dir=CACHE_DIR):
+ """Generate a palette."""
+ # home_dylan_img_jpg_backend_1.2.2.json
+ cache_name = cache_fname(img, backend, light, cache_dir)
+ cache_file = os.path.join(*cache_name)
if os.path.isfile(cache_file):
colors = theme.file(cache_file)
@@ -120,8 +94,15 @@ def get(img, cache_dir=CACHE_DIR,
else:
print("wal: Generating a colorscheme...")
- colors = gen_colors(img, color_count)
- colors = create_palette(img, colors, light)
+ # Dynamically import the backend we want to use.
+ # This keeps the dependencies "optional".
+ try:
+ __import__("pywal.backends.%s" % backend)
+ except ImportError:
+ backend = "wal"
+
+ backend = sys.modules["pywal.backends.%s" % backend]
+ colors = colors_to_dict(getattr(backend, "get")(img, light), img)
util.save_file_json(colors, cache_file)
print("wal: Generation complete.")
diff --git a/pywal/reload.py b/pywal/reload.py
index 9426cfb..e815d64 100644
--- a/pywal/reload.py
+++ b/pywal/reload.py
@@ -10,11 +10,11 @@ from .settings import CACHE_DIR, MODULE_DIR, OS
from . import util
-def tty():
+def tty(tty_reload):
"""Load colors in tty."""
tty_script = os.path.join(CACHE_DIR, "colors-tty.sh")
- if os.path.isfile(tty_script):
+ if os.path.isfile(tty_script) and tty_reload:
subprocess.Popen(["sh", tty_script])
@@ -87,11 +87,11 @@ def colors(cache_dir=CACHE_DIR):
print("".join(util.read_file(sequences)), end="")
-def env(xrdb_file=None):
+def env(xrdb_file=None, tty_reload=True):
"""Reload environment."""
xrdb(xrdb_file)
i3()
sway()
polybar()
print("reload: Reloaded environment.")
- tty()
+ tty(tty_reload)
diff --git a/pywal/sequences.py b/pywal/sequences.py
index ecb79e3..0376342 100644
--- a/pywal/sequences.py
+++ b/pywal/sequences.py
@@ -73,7 +73,7 @@ def create_sequences(colors):
return "".join(sequences)
-def send(colors, cache_dir=CACHE_DIR):
+def send(colors, cache_dir=CACHE_DIR, to_send=True):
"""Send colors to all open terminals."""
if OS == "Darwin":
tty_pattern = "/dev/ttys00[0-9]*"
@@ -84,8 +84,9 @@ def send(colors, cache_dir=CACHE_DIR):
sequences = create_sequences(colors)
# Writing to "/dev/pts/[0-9] lets you send data to open terminals.
- for term in glob.glob(tty_pattern):
- util.save_file(sequences, term)
+ if to_send:
+ for term in glob.glob(tty_pattern):
+ util.save_file(sequences, term)
util.save_file(sequences, os.path.join(cache_dir, "sequences"))
print("colors: Set terminal colors.")
diff --git a/pywal/settings.py b/pywal/settings.py
index ca82333..fd12105 100644
--- a/pywal/settings.py
+++ b/pywal/settings.py
@@ -21,5 +21,4 @@ HOME = os.getenv("HOME", os.getenv("USERPROFILE"))
CACHE_DIR = os.path.join(HOME, ".cache", "wal")
MODULE_DIR = os.path.dirname(__file__)
CONF_DIR = os.path.join(HOME, ".config", "wal")
-COLOR_COUNT = 16
OS = platform.uname()[0]
diff --git a/pywal/util.py b/pywal/util.py
index 43ee3fb..65d4557 100644
--- a/pywal/util.py
+++ b/pywal/util.py
@@ -144,6 +144,11 @@ def saturate_color(color, amount):
return rgb_to_hex((int(r), int(g), int(b)))
+def rgb_to_yiq(color):
+ """Sort a list of colors."""
+ return colorsys.rgb_to_yiq(*hex_to_rgb(color))
+
+
def disown(cmd):
"""Call a system command in the background,
disown it and hide it's output."""