From d487f5e5cb22e58e5ec164e20168b39a75ca39e8 Mon Sep 17 00:00:00 2001 From: Fuwn Date: Thu, 12 Sep 2024 11:29:21 +0000 Subject: feat: more backends --- pywal/backends/__init__.py | 0 pywal/backends/colorthief.py | 79 ++++++++++++++++++++++++++++++++ pywal/backends/colorz.py | 60 +++++++++++++++++++++++++ pywal/backends/wal.py | 105 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 244 insertions(+) create mode 100644 pywal/backends/__init__.py create mode 100644 pywal/backends/colorthief.py create mode 100644 pywal/backends/colorz.py create mode 100644 pywal/backends/wal.py (limited to 'pywal/backends') diff --git a/pywal/backends/__init__.py b/pywal/backends/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pywal/backends/colorthief.py b/pywal/backends/colorthief.py new file mode 100644 index 0000000..f1d52f7 --- /dev/null +++ b/pywal/backends/colorthief.py @@ -0,0 +1,79 @@ +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +""" +Generate a colorscheme using ColorThief. +""" + +import logging +import sys + +try: + from colorthief import ColorThief + +except ImportError: + logging.error("ColorThief wasn't found on your system.") + logging.error("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 + + if i == 10: + logging.error("ColorThief couldn't generate a suitable palette.") + sys.exit(1) + + 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..f05e534 --- /dev/null +++ b/pywal/backends/colorz.py @@ -0,0 +1,60 @@ +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +""" +Generate a colorscheme using Colorz. +""" +import logging +import sys + +try: + import colorz + +except ImportError: + logging.error("colorz wasn't found on your system.") + logging.error("Try another backend. (wal --backend)") + sys.exit(1) + +from .. import colors +from .. import util + + +def gen_colors(img): + """Generate a colorscheme using Colorz.""" + # pylint: disable=not-callable + raw_colors = colorz.colorz(img, n=6, bold_add=0) + return [util.rgb_to_hex([*color[0]]) for color in raw_colors] + + +def adjust(cols, light): + """Create palette.""" + raw_colors = [cols[0], *cols, "#FFFFFF", "#000000", *cols, "#FFFFFF"] + + return colors.generic_adjust(raw_colors, light) + + +def get(img, light=False): + """Get colorscheme.""" + cols = gen_colors(img) + + if len(cols) < 6: + logging.error("colorz failed to generate enough colors.") + logging.error("Try another backend or another image. (wal --backend)") + sys.exit(1) + + return adjust(cols, light) diff --git a/pywal/backends/wal.py b/pywal/backends/wal.py new file mode 100644 index 0000000..883abb6 --- /dev/null +++ b/pywal/backends/wal.py @@ -0,0 +1,105 @@ +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +""" +Generate a colorscheme using imagemagick. +""" + +import logging +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"] + + if shutil.which("convert"): + return ["convert"] + + logging.error("Imagemagick wasn't found on your system.") + logging.error("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 + + if i == 19: + logging.error("Imagemagick couldn't generate a suitable palette.") + sys.exit(1) + + else: + logging.warning("Imagemagick couldn't generate a palette.") + logging.warning("Trying a larger palette size %s", 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.40) + + 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) -- cgit v1.2.3