Made a module out of this project
This commit is contained in:
parent
048805bf04
commit
3387314575
228
huepaper.py
228
huepaper.py
@ -1,228 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from huepaper import (
|
||||
get_base_color,
|
||||
create_colors,
|
||||
create_base_image,
|
||||
add_lines,
|
||||
add_pixelation,
|
||||
add_emblem,
|
||||
)
|
||||
import argparse
|
||||
import os
|
||||
|
||||
|
||||
def print_greeter():
|
||||
greeter = """
|
||||
.lk.
|
||||
cO.
|
||||
cO.;:lc. ,c. .cc .,',c; .,c.;coc. ;,.,c. ':l.:lo: '',:c. '::.lo.
|
||||
cO' kd .O; dO ,x...,Ox cO; lO: ;x xk OO. .kO. x;...x0' 0x. .
|
||||
cO. xx .O; dO ko...... :O. Ox .,..xO kk ;0;;0...... 0d
|
||||
cO. xx .O; xO dO. .. :O. .O; dk xO kk :O.'0o , 0d
|
||||
.dk, .kk. okc;,ox' ckxllc. :Oc'.,l' oOl;'dO:. kO;..:l. ,xOolc; ,Ox.
|
||||
:O. kk
|
||||
lO, OO
|
||||
OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO00O0000000000000000;
|
||||
"""
|
||||
print(greeter)
|
||||
|
||||
|
||||
def save_image(image, filepath):
|
||||
"""Save an image at given filepath."""
|
||||
save = True
|
||||
|
||||
# Check whether file exists
|
||||
if os.path.isfile(filepath):
|
||||
overwrite = input(
|
||||
"The file {} already exists. Do you want to overwrite it? [y/N] ".format(
|
||||
filepath
|
||||
)
|
||||
)
|
||||
if overwrite != "y" and overwrite != "Y":
|
||||
save = False
|
||||
|
||||
if save:
|
||||
|
||||
stop = False
|
||||
while not stop:
|
||||
try:
|
||||
image.save(filepath)
|
||||
stop = True
|
||||
except Exception as e:
|
||||
print("Failed to save wallpaper: {}".format(e))
|
||||
again = input("Do you want to try again? [Y/n] ")
|
||||
if again == "n" or again == "N":
|
||||
stop = True
|
||||
else:
|
||||
filepath = input(
|
||||
"Please enter new path where the wallpaper shall be saved: "
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Create wallpapers based on color hues."
|
||||
)
|
||||
parser.add_argument(
|
||||
"-s",
|
||||
"--size",
|
||||
default="1920x1080",
|
||||
help="size of huepaper in the form WIDTHxHEIGHT (default: 1920x1080)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
"--color",
|
||||
help="base color from which the huepaper is generated (default: random color)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-np", "--no-preview", action="store_true", help="don't preview the huepaper"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-o", "--output", help="filepath where the huepaper will be saved"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-l",
|
||||
"--lines",
|
||||
nargs="?",
|
||||
const=0.3,
|
||||
type=float,
|
||||
help="include one to three random lines in base color with given opacity in range [0, 1] (default: 0.3)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-lb",
|
||||
"--lines_bright",
|
||||
nargs="?",
|
||||
const=0.1,
|
||||
type=float,
|
||||
help="include one to three bright random lines with given opacity in range [0, 1] (default: 0.1)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-ld",
|
||||
"--lines_dark",
|
||||
nargs="?",
|
||||
const=0.1,
|
||||
type=float,
|
||||
help="include one to three dark random lines with given opacity in range [0, 1] (default: 0.1)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-p",
|
||||
"--pixelate",
|
||||
nargs="?",
|
||||
const="16x9",
|
||||
help="pixelate image with WIDTHxHEIGHT (default: 16x9)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-e", "--emblem", help="emblem to add in the center of the huepaper"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-hue",
|
||||
default=0.1,
|
||||
type=float,
|
||||
help="maximum hue to differ from given color in range [0, 1] (default: 0.1)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-smin",
|
||||
default=0.2,
|
||||
type=float,
|
||||
help="minimum saturation for colors in range [0, 1] (default: 0.2)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-smax",
|
||||
default=1.0,
|
||||
type=float,
|
||||
help="maximum saturation for colors in range [0, 1] (default: 1.0)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-lmin",
|
||||
default=0.2,
|
||||
type=float,
|
||||
help="minimum luminance for colors in range [0, 1] (default: 0.2)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-lmax",
|
||||
default=0.9,
|
||||
type=float,
|
||||
help="maximum luminance for colors in range [0, 1] (default: 0.9)",
|
||||
)
|
||||
|
||||
# Get args
|
||||
args = parser.parse_args()
|
||||
size = args.size
|
||||
color = args.color
|
||||
no_preview = args.no_preview
|
||||
output = args.output
|
||||
lines = args.lines
|
||||
lines_bright = args.lines_bright
|
||||
lines_dark = args.lines_dark
|
||||
emblem = args.emblem
|
||||
pixelate = args.pixelate
|
||||
hue_max = args.hue
|
||||
sat_min = args.smin
|
||||
sat_max = args.smax
|
||||
lum_min = args.lmin
|
||||
lum_max = args.lmax
|
||||
|
||||
# Get size
|
||||
try:
|
||||
values = size.split("x")
|
||||
width = int(values[0])
|
||||
height = int(values[1])
|
||||
except:
|
||||
parser.error("The size must be given in form: 1920x1080")
|
||||
|
||||
# Check preconditions
|
||||
if no_preview and not output:
|
||||
parser.error("You must either omit -np (--no-preview) or set -o (--output)")
|
||||
if pixelate:
|
||||
try:
|
||||
values = pixelate.split("x")
|
||||
px = int(values[0])
|
||||
py = int(values[1])
|
||||
except:
|
||||
parser.error("Pixelation value must be set in form: 42x42")
|
||||
|
||||
print_greeter()
|
||||
|
||||
try:
|
||||
random_color = False if color else True
|
||||
base_color = get_base_color(color, sat_min, sat_max, lum_min, lum_max)
|
||||
if random_color:
|
||||
print("Selected random base color: {}".format(base_color.hex))
|
||||
|
||||
c1, c2, c3, c4 = create_colors(
|
||||
base_color, hue_max, sat_min, sat_max, lum_min, lum_max
|
||||
)
|
||||
|
||||
image = create_base_image(c1, c2, c3, c4, width, height)
|
||||
|
||||
if lines:
|
||||
image = add_lines(image, base_color.rgb + (lines,))
|
||||
if lines_bright:
|
||||
image = add_lines(image, (1.0, 1.0, 1.0, lines_bright))
|
||||
if lines_dark:
|
||||
image = add_lines(image, (0.0, 0.0, 0.0, lines_dark))
|
||||
|
||||
if pixelate:
|
||||
image = add_pixelation(image, px, py)
|
||||
|
||||
if emblem:
|
||||
image = add_emblem(image, emblem)
|
||||
|
||||
image.mode = "RGB"
|
||||
|
||||
if not no_preview:
|
||||
image.show()
|
||||
if not output:
|
||||
save = input("Do you want to save the image? [y/N] ")
|
||||
if save == "y" or save == "Y":
|
||||
path = input("Enter the path where the wallpaper shall be saved: ")
|
||||
save_image(image, path)
|
||||
|
||||
if output:
|
||||
save_image(image, output)
|
||||
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
exit(1)
|
@ -1,155 +1,2 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from PIL import Image, ImageDraw, ImageOps
|
||||
from colour import Color
|
||||
import numpy as np
|
||||
import random
|
||||
|
||||
|
||||
def get_base_color(
|
||||
color_string=None, sat_min=0.2, sat_max=1.0, lum_min=0.2, lum_max=0.9
|
||||
):
|
||||
"""Get base color for a huepaper by color string."""
|
||||
# If no color string is given, create a random color
|
||||
if not color_string:
|
||||
hue = random.uniform(0, 1)
|
||||
sat = random.uniform(sat_min, sat_max)
|
||||
lum = random.uniform(lum_min, lum_max)
|
||||
base_color = Color(hue=hue, saturation=sat, luminance=lum)
|
||||
|
||||
# Else try to parse string
|
||||
else:
|
||||
try:
|
||||
base_color = Color(color_string)
|
||||
except:
|
||||
try:
|
||||
base_color = Color("#{}".format(color_string))
|
||||
except:
|
||||
raise Exception("Invalid color expression: {}".format(color_string))
|
||||
|
||||
return base_color
|
||||
|
||||
|
||||
def create_colors(
|
||||
base_color=None, hue_max=0.1, sat_min=0.2, sat_max=1.0, lum_min=0.3, lum_max=0.9
|
||||
):
|
||||
"""Create four corner colors for a huepaper by an optional base color."""
|
||||
if not base_color:
|
||||
base_color = get_base_color(None, sat_min, sat_max, lum_min, lum_max)
|
||||
|
||||
colors = []
|
||||
|
||||
max_sat_diff = 0.1
|
||||
max_lum_diff = 0.1
|
||||
|
||||
# Create four random colors similar to the given base_color
|
||||
for i in range(0, 4):
|
||||
|
||||
tmp_hue = base_color.hue + random.uniform(-hue_max / 2.0, hue_max / 2.0)
|
||||
if tmp_hue > 1.0:
|
||||
tmp_hue -= 1
|
||||
|
||||
tmp_sat = base_color.saturation + random.uniform(-max_sat_diff, max_sat_diff)
|
||||
tmp_sat = min(sat_max, max(sat_min, tmp_sat))
|
||||
|
||||
tmp_lum = base_color.luminance + random.uniform(-max_lum_diff, max_lum_diff)
|
||||
tmp_lum = min(lum_max, max(lum_min, tmp_lum))
|
||||
|
||||
color = Color(hue=tmp_hue, saturation=tmp_sat, luminance=tmp_lum)
|
||||
colors.append(color.rgb)
|
||||
|
||||
return tuple(colors)
|
||||
|
||||
|
||||
def create_base_image(c1, c2, c3, c4, width=1920, height=1080):
|
||||
"""Create a base huepaper by four corner colors.
|
||||
|
||||
c1 - top left
|
||||
c2 - top right
|
||||
c3 - bottom right
|
||||
c4 - bottom left
|
||||
"""
|
||||
r = np.linspace(
|
||||
np.linspace(c1[0], c4[0], height), np.linspace(c2[0], c3[0], height), width
|
||||
)
|
||||
g = np.linspace(
|
||||
np.linspace(c1[1], c4[1], height), np.linspace(c2[1], c3[1], height), width
|
||||
)
|
||||
b = np.linspace(
|
||||
np.linspace(c1[2], c4[2], height), np.linspace(c2[2], c3[2], height), width
|
||||
)
|
||||
|
||||
im_arr = np.array([r, g, b]).T
|
||||
image = Image.fromarray(np.uint8(im_arr * 255)).convert("RGBA")
|
||||
|
||||
return image
|
||||
|
||||
|
||||
def add_lines(image, color):
|
||||
"""Add one to three random lines to an image with given color."""
|
||||
width, height = image.size
|
||||
|
||||
line_image = Image.new("RGBA", (width, height), (0, 0, 0, 0))
|
||||
draw = ImageDraw.Draw(line_image)
|
||||
|
||||
# Set color
|
||||
color = tuple(map(lambda x: int(x * 255), color))
|
||||
|
||||
# Generate lines
|
||||
number_of_lines = random.randint(1, 3)
|
||||
scale = width / 100.0
|
||||
base_width = random.randint(int(2 * scale), int(5 * scale))
|
||||
rand_width = lambda base_width=base_width: base_width + random.randint(
|
||||
-base_width // 2, base_width // 2
|
||||
)
|
||||
space = rand_width() // 2
|
||||
offset = random.randint(0, space)
|
||||
for i in range(0, number_of_lines):
|
||||
line_width = rand_width()
|
||||
x = offset + space + (line_width // 2)
|
||||
draw.line((x, 0, x, height), fill=color, width=line_width)
|
||||
offset += space + line_width
|
||||
|
||||
# Mirror line image eventually
|
||||
orientation = random.randrange(2)
|
||||
if orientation == 1:
|
||||
line_image = ImageOps.mirror(line_image)
|
||||
|
||||
# Add line image to input image
|
||||
image.alpha_composite(line_image, (0, 0))
|
||||
|
||||
return image
|
||||
|
||||
|
||||
def add_pixelation(image, x=16, y=9):
|
||||
"""Pixelate an image."""
|
||||
width, height = image.size
|
||||
|
||||
image = image.resize((x, y))
|
||||
image = image.resize((width, height), Image.BOX)
|
||||
|
||||
return image
|
||||
|
||||
|
||||
def add_emblem(image, filepath):
|
||||
"""Add an amblem to an image by filepath."""
|
||||
width, height = image.size
|
||||
|
||||
# Load image
|
||||
try:
|
||||
emblem_image = Image.open(filepath)
|
||||
except Exception as e:
|
||||
raise Exception("Failed to load emblem: {}".format(e))
|
||||
|
||||
# Exit if emblem is too big
|
||||
if emblem_image.size[0] > width or emblem_image.size[1] > height:
|
||||
raise Exception("Emblem can't be bigger than the huepaper")
|
||||
|
||||
# Insert emblem in the center
|
||||
offset = (
|
||||
(image.size[0] - emblem_image.size[0]) // 2,
|
||||
(image.size[1] - emblem_image.size[1]) // 2,
|
||||
)
|
||||
image.alpha_composite(emblem_image, offset)
|
||||
|
||||
return image
|
||||
from . import utils
|
||||
from .generator import generate
|
||||
|
134
huepaper/__main__.py
Normal file
134
huepaper/__main__.py
Normal file
@ -0,0 +1,134 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import argparse
|
||||
from huepaper import generate
|
||||
|
||||
|
||||
def print_greeter():
|
||||
greeter = """
|
||||
.lk.
|
||||
cO.
|
||||
cO.;:lc. ,c. .cc .,',c; .,c.;coc. ;,.,c. ':l.:lo: '',:c. '::.lo.
|
||||
cO' kd .O; dO ,x...,Ox cO; lO: ;x xk OO. .kO. x;...x0' 0x. .
|
||||
cO. xx .O; dO ko...... :O. Ox .,..xO kk ;0;;0...... 0d
|
||||
cO. xx .O; xO dO. .. :O. .O; dk xO kk :O.'0o , 0d
|
||||
.dk, .kk. okc;,ox' ckxllc. :Oc'.,l' oOl;'dO:. kO;..:l. ,xOolc; ,Ox.
|
||||
:O. kk
|
||||
lO, OO
|
||||
OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO00O0000000000000000;
|
||||
"""
|
||||
print(greeter)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Create wallpapers based on color hues."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--width",
|
||||
default=1920,
|
||||
help="width of the image (default: 1920)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--height",
|
||||
default=1080,
|
||||
help="height of the image (default: 1080)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-o", "--output", help="filepath where the huepaper will be saved"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
"--color",
|
||||
help="base color from which the huepaper is generated (default: random color)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-l",
|
||||
"--lines",
|
||||
nargs="?",
|
||||
const=0.3,
|
||||
type=float,
|
||||
help="include one to three random lines in base color with given opacity in range [0, 1] (default: 0.3)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-lb",
|
||||
"--lines_bright",
|
||||
nargs="?",
|
||||
const=0.1,
|
||||
type=float,
|
||||
help="include one to three bright random lines with given opacity in range [0, 1] (default: 0.1)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-ld",
|
||||
"--lines_dark",
|
||||
nargs="?",
|
||||
const=0.1,
|
||||
type=float,
|
||||
help="include one to three dark random lines with given opacity in range [0, 1] (default: 0.1)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-p",
|
||||
"--pixelate",
|
||||
nargs="?",
|
||||
const="16x9",
|
||||
help="pixelate image with WIDTHxHEIGHT (default: 16x9)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-e", "--emblem", help="emblem to add in the center of the huepaper"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-hue",
|
||||
default=0.1,
|
||||
type=float,
|
||||
help="maximum hue to differ from given color in range [0, 1] (default: 0.1)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-smin",
|
||||
default=0.2,
|
||||
type=float,
|
||||
help="minimum saturation for colors in range [0, 1] (default: 0.2)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-smax",
|
||||
default=1.0,
|
||||
type=float,
|
||||
help="maximum saturation for colors in range [0, 1] (default: 1.0)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-lmin",
|
||||
default=0.2,
|
||||
type=float,
|
||||
help="minimum luminance for colors in range [0, 1] (default: 0.2)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-lmax",
|
||||
default=0.9,
|
||||
type=float,
|
||||
help="maximum luminance for colors in range [0, 1] (default: 0.9)",
|
||||
)
|
||||
|
||||
# Get args
|
||||
args = parser.parse_args()
|
||||
|
||||
print(args)
|
||||
|
||||
generate(
|
||||
_output=args.output,
|
||||
width=args.width,
|
||||
height=args.height,
|
||||
color=args.color,
|
||||
lines=args.lines,
|
||||
lines_bright=args.lines_bright,
|
||||
lines_dark=args.lines_dark,
|
||||
emblem=args.emblem,
|
||||
pixelate=args.pixelate,
|
||||
hue_max=args.hue,
|
||||
sat_min=args.smin,
|
||||
sat_max=args.smax,
|
||||
lum_min=args.lmin,
|
||||
lum_max=args.lmax,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
81
huepaper/generator.py
Normal file
81
huepaper/generator.py
Normal file
@ -0,0 +1,81 @@
|
||||
from pathlib import Path
|
||||
from typing import Union
|
||||
|
||||
from PIL import Image
|
||||
|
||||
from huepaper.utils import (
|
||||
add_emblem,
|
||||
add_lines,
|
||||
add_pixelation,
|
||||
create_base_image,
|
||||
create_colors,
|
||||
get_base_color,
|
||||
save_image,
|
||||
)
|
||||
|
||||
|
||||
def generate(
|
||||
width: int = 1920,
|
||||
height: int = 1080,
|
||||
color: Union[str, None] = None,
|
||||
lines: Union[float, None] = None,
|
||||
lines_bright: Union[float, None] = None,
|
||||
lines_dark: Union[float, None] = None,
|
||||
emblem: Union[str, Path, None] = None,
|
||||
pixelate: Union[str, None] = None,
|
||||
hue_max: float = 0.1,
|
||||
sat_min: float = 0.2,
|
||||
sat_max: float = 1.0,
|
||||
lum_min: float = 0.2,
|
||||
lum_max: float = 0.9,
|
||||
_output: Union[str, Path, None] = None,
|
||||
) -> Image:
|
||||
# Get size
|
||||
if width is None or height is None:
|
||||
raise ValueError("The size must be provided")
|
||||
|
||||
# Check preconditions
|
||||
if pixelate:
|
||||
try:
|
||||
values = pixelate.split("x")
|
||||
px = int(values[0])
|
||||
py = int(values[1])
|
||||
except:
|
||||
raise ValueError("Pixelation value must be set in form: 42x42")
|
||||
|
||||
try:
|
||||
random_color = False if color else True
|
||||
base_color = get_base_color(color, sat_min, sat_max, lum_min, lum_max)
|
||||
if random_color:
|
||||
print("Selected random base color: {}".format(base_color.hex))
|
||||
|
||||
c1, c2, c3, c4 = create_colors(
|
||||
base_color, hue_max, sat_min, sat_max, lum_min, lum_max
|
||||
)
|
||||
|
||||
image = create_base_image(c1, c2, c3, c4, width, height)
|
||||
|
||||
if lines:
|
||||
image = add_lines(image, base_color.rgb + (lines,))
|
||||
if lines_bright:
|
||||
image = add_lines(image, (1.0, 1.0, 1.0, lines_bright))
|
||||
if lines_dark:
|
||||
image = add_lines(image, (0.0, 0.0, 0.0, lines_dark))
|
||||
|
||||
if pixelate:
|
||||
image = add_pixelation(image, px, py)
|
||||
|
||||
if emblem:
|
||||
image = add_emblem(image, emblem)
|
||||
|
||||
image.mode = "RGB"
|
||||
|
||||
if _output:
|
||||
save_image(image, _output)
|
||||
return
|
||||
|
||||
return image
|
||||
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
exit(1)
|
185
huepaper/utils.py
Normal file
185
huepaper/utils.py
Normal file
@ -0,0 +1,185 @@
|
||||
import os
|
||||
import random
|
||||
|
||||
import numpy as np
|
||||
from colour import Color
|
||||
from PIL import Image, ImageDraw, ImageOps
|
||||
|
||||
|
||||
def get_base_color(
|
||||
color_string=None, sat_min=0.2, sat_max=1.0, lum_min=0.2, lum_max=0.9
|
||||
):
|
||||
"""Get base color for a huepaper by color string."""
|
||||
# If no color string is given, create a random color
|
||||
if not color_string:
|
||||
hue = random.uniform(0, 1)
|
||||
sat = random.uniform(sat_min, sat_max)
|
||||
lum = random.uniform(lum_min, lum_max)
|
||||
base_color = Color(hue=hue, saturation=sat, luminance=lum)
|
||||
|
||||
# Else try to parse string
|
||||
else:
|
||||
try:
|
||||
base_color = Color(color_string)
|
||||
except:
|
||||
try:
|
||||
base_color = Color("#{}".format(color_string))
|
||||
except:
|
||||
raise Exception("Invalid color expression: {}".format(color_string))
|
||||
|
||||
return base_color
|
||||
|
||||
|
||||
def create_colors(
|
||||
base_color=None, hue_max=0.1, sat_min=0.2, sat_max=1.0, lum_min=0.3, lum_max=0.9
|
||||
):
|
||||
"""Create four corner colors for a huepaper by an optional base color."""
|
||||
if not base_color:
|
||||
base_color = get_base_color(None, sat_min, sat_max, lum_min, lum_max)
|
||||
|
||||
colors = []
|
||||
|
||||
max_sat_diff = 0.1
|
||||
max_lum_diff = 0.1
|
||||
|
||||
# Create four random colors similar to the given base_color
|
||||
for i in range(0, 4):
|
||||
tmp_hue = base_color.hue + random.uniform(-hue_max / 2.0, hue_max / 2.0)
|
||||
if tmp_hue > 1.0:
|
||||
tmp_hue -= 1
|
||||
|
||||
tmp_sat = base_color.saturation + random.uniform(-max_sat_diff, max_sat_diff)
|
||||
tmp_sat = min(sat_max, max(sat_min, tmp_sat))
|
||||
|
||||
tmp_lum = base_color.luminance + random.uniform(-max_lum_diff, max_lum_diff)
|
||||
tmp_lum = min(lum_max, max(lum_min, tmp_lum))
|
||||
|
||||
color = Color(hue=tmp_hue, saturation=tmp_sat, luminance=tmp_lum)
|
||||
colors.append(color.rgb)
|
||||
|
||||
return tuple(colors)
|
||||
|
||||
|
||||
def create_base_image(c1, c2, c3, c4, width=1920, height=1080):
|
||||
"""Create a base huepaper by four corner colors.
|
||||
|
||||
c1 - top left
|
||||
c2 - top right
|
||||
c3 - bottom right
|
||||
c4 - bottom left
|
||||
"""
|
||||
r = np.linspace(
|
||||
np.linspace(c1[0], c4[0], height), np.linspace(c2[0], c3[0], height), width
|
||||
)
|
||||
g = np.linspace(
|
||||
np.linspace(c1[1], c4[1], height), np.linspace(c2[1], c3[1], height), width
|
||||
)
|
||||
b = np.linspace(
|
||||
np.linspace(c1[2], c4[2], height), np.linspace(c2[2], c3[2], height), width
|
||||
)
|
||||
|
||||
im_arr = np.array([r, g, b]).T
|
||||
image = Image.fromarray(np.uint8(im_arr * 255)).convert("RGBA")
|
||||
|
||||
return image
|
||||
|
||||
|
||||
def add_lines(image, color):
|
||||
"""Add one to three random lines to an image with given color."""
|
||||
width, height = image.size
|
||||
|
||||
line_image = Image.new("RGBA", (width, height), (0, 0, 0, 0))
|
||||
draw = ImageDraw.Draw(line_image)
|
||||
|
||||
# Set color
|
||||
color = tuple(map(lambda x: int(x * 255), color))
|
||||
|
||||
# Generate lines
|
||||
number_of_lines = random.randint(1, 3)
|
||||
scale = width / 100.0
|
||||
base_width = random.randint(int(2 * scale), int(5 * scale))
|
||||
rand_width = lambda base_width=base_width: base_width + random.randint(
|
||||
-base_width // 2, base_width // 2
|
||||
)
|
||||
space = rand_width() // 2
|
||||
offset = random.randint(0, space)
|
||||
for i in range(0, number_of_lines):
|
||||
line_width = rand_width()
|
||||
x = offset + space + (line_width // 2)
|
||||
draw.line((x, 0, x, height), fill=color, width=line_width)
|
||||
offset += space + line_width
|
||||
|
||||
# Mirror line image eventually
|
||||
orientation = random.randrange(2)
|
||||
if orientation == 1:
|
||||
line_image = ImageOps.mirror(line_image)
|
||||
|
||||
# Add line image to input image
|
||||
image.alpha_composite(line_image, (0, 0))
|
||||
|
||||
return image
|
||||
|
||||
|
||||
def add_pixelation(image, x=16, y=9):
|
||||
"""Pixelate an image."""
|
||||
width, height = image.size
|
||||
|
||||
image = image.resize((x, y))
|
||||
image = image.resize((width, height), Image.BOX)
|
||||
|
||||
return image
|
||||
|
||||
|
||||
def add_emblem(image, filepath):
|
||||
"""Add an amblem to an image by filepath."""
|
||||
width, height = image.size
|
||||
|
||||
# Load image
|
||||
try:
|
||||
emblem_image = Image.open(filepath)
|
||||
except Exception as e:
|
||||
raise Exception("Failed to load emblem: {}".format(e))
|
||||
|
||||
# Exit if emblem is too big
|
||||
if emblem_image.size[0] > width or emblem_image.size[1] > height:
|
||||
raise Exception("Emblem can't be bigger than the huepaper")
|
||||
|
||||
# Insert emblem in the center
|
||||
offset = (
|
||||
(image.size[0] - emblem_image.size[0]) // 2,
|
||||
(image.size[1] - emblem_image.size[1]) // 2,
|
||||
)
|
||||
image.alpha_composite(emblem_image, offset)
|
||||
|
||||
return image
|
||||
|
||||
|
||||
def save_image(image, filepath):
|
||||
"""Save an image at given filepath."""
|
||||
save = True
|
||||
|
||||
# Check whether file exists
|
||||
if os.path.isfile(filepath):
|
||||
overwrite = input(
|
||||
"The file {} already exists. Do you want to overwrite it? [y/N] ".format(
|
||||
filepath
|
||||
)
|
||||
)
|
||||
if overwrite != "y" and overwrite != "Y":
|
||||
save = False
|
||||
|
||||
if save:
|
||||
stop = False
|
||||
while not stop:
|
||||
try:
|
||||
image.save(filepath)
|
||||
stop = True
|
||||
except Exception as e:
|
||||
print("Failed to save wallpaper: {}".format(e))
|
||||
again = input("Do you want to try again? [Y/n] ")
|
||||
if again == "n" or again == "N":
|
||||
stop = True
|
||||
else:
|
||||
filepath = input(
|
||||
"Please enter new path where the wallpaper shall be saved: "
|
||||
)
|
47
pyproject.toml
Normal file
47
pyproject.toml
Normal file
@ -0,0 +1,47 @@
|
||||
[build-system]
|
||||
requires = ["setuptools>=52.0"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "huepaper"
|
||||
version = "0.0.2"
|
||||
dynamic = ["dependencies"]
|
||||
authors = [{ name = "Denis Lehmann" }]
|
||||
maintainers = [{ name = "Profitroll" }]
|
||||
description = "A colorful wallpaper generator"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.8"
|
||||
license = { text = "GPL3" }
|
||||
classifiers = [
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Operating System :: OS Independent",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.7",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
"Topic :: Utilities",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
Source = "https://git.end-play.xyz/profitroll/huepaper"
|
||||
Tracker = "https://git.end-play.xyz/profitroll/huepaper/issues"
|
||||
|
||||
[project.scripts]
|
||||
huepaper = "huepaper.__main__:main"
|
||||
|
||||
[tool.setuptools]
|
||||
packages = ["huepaper"]
|
||||
|
||||
[tool.setuptools.dynamic]
|
||||
dependencies = { file = "requirements.txt" }
|
||||
|
||||
[tool.black]
|
||||
target-version = ['py37', 'py38', 'py39', 'py310', 'py311']
|
||||
|
||||
[tool.isort]
|
||||
profile = "black"
|
@ -1,3 +1,3 @@
|
||||
colour
|
||||
numpy
|
||||
pillow
|
||||
colour==0.1.5
|
||||
numpy~=1.25.2
|
||||
pillow~=10.0.0
|
21
setup.py
21
setup.py
@ -1,21 +0,0 @@
|
||||
from setuptools import setup
|
||||
import os
|
||||
import shutil
|
||||
|
||||
if not os.path.exists("bin"):
|
||||
os.makedirs("bin")
|
||||
shutil.copyfile("huepaper.py", "bin/huepaper")
|
||||
|
||||
setup(
|
||||
name="huepaper",
|
||||
version="0.0.1",
|
||||
author="Denis Lehmann",
|
||||
author_email="denis@opaque.tech",
|
||||
scripts=["bin/huepaper"],
|
||||
packages=["huepaper"],
|
||||
url="https://git.opaque.tech/denis/huepaper",
|
||||
license="LICENSE",
|
||||
description="A colorful wallpaper generator",
|
||||
long_description=open("README.org").read(),
|
||||
install_requires=["colour", "numpy", "pillow"],
|
||||
)
|
36
tests/test_500x500.py
Normal file
36
tests/test_500x500.py
Normal file
@ -0,0 +1,36 @@
|
||||
from os import remove
|
||||
from pathlib import Path
|
||||
|
||||
from PIL.Image import Image
|
||||
|
||||
from huepaper import generate
|
||||
from huepaper.utils import save_image
|
||||
|
||||
|
||||
def test_generation():
|
||||
image = generate(
|
||||
width=500,
|
||||
height=500,
|
||||
hue_max=1.0,
|
||||
lum_min=0.3,
|
||||
lum_max=0.6,
|
||||
sat_min=0.8,
|
||||
sat_max=1.0,
|
||||
)
|
||||
assert isinstance(image, Image)
|
||||
|
||||
|
||||
def test_saving():
|
||||
image = generate(
|
||||
500,
|
||||
500,
|
||||
hue_max=1.0,
|
||||
lum_min=0.3,
|
||||
lum_max=0.6,
|
||||
sat_min=0.8,
|
||||
sat_max=1.0,
|
||||
lines=0.0,
|
||||
)
|
||||
save_image(image, Path("tests/image.jpg"))
|
||||
assert Path("tests/image.jpg").exists()
|
||||
remove(Path("tests/image.jpg"))
|
Loading…
Reference in New Issue
Block a user