From 42852bc0477384008e78a9f562a2c3f7cdb71a30 Mon Sep 17 00:00:00 2001 From: Denis Lehmann Date: Wed, 14 Jul 2021 17:08:24 +0200 Subject: [PATCH] cleanup --- huepaper.org | 438 --------------------------------------------------- huepaper.py | 32 +++- 2 files changed, 25 insertions(+), 445 deletions(-) delete mode 100644 huepaper.org diff --git a/huepaper.org b/huepaper.org deleted file mode 100644 index f4f1f58..0000000 --- a/huepaper.org +++ /dev/null @@ -1,438 +0,0 @@ -* huepaper -:PROPERTIES: -:header-args: :tangle huepaper.py :shebang "#!/usr/bin/env python" -:END: - -This is the literate programming file for =huepaper.py=. -To export it, open it in *Emacs* and *tangle* it. - -** Imports - -huepaper is mainly based on two libraries. -[[https://github.com/vaab/colour][Colour]] and [[https://python-pillow.org/][Pillow]]. - -#+BEGIN_SRC python - import argparse - import os.path - import random - import sys - from colour import Color - from PIL import Image, ImageDraw, ImageOps -#+END_SRC - -** Logo - -The logo of huepaper is printed on startup. - -#+BEGIN_SRC python - def print_logo(): - logo = """ - .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(logo) -#+END_SRC - -** Base color - -Every huepaper has a base color. -It is used to calculate the final colors. - -If a base color is given by the user, it can have every format, Colour supports. -If no color is given, a random one is chosen. - -#+BEGIN_SRC python - def get_base_color(color_string=None): - - # 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) - print("Selected random base color: {}".format(base_color.hex)) - - # Else try to parse string - else: - try: - base_color = Color(color_string) - except: - print("Not a valid color expression: {}".format(color_string)) - sys.exit(1) - - return base_color -#+END_SRC - -** Colors - -The final color limits for each edge of the huepaper are calculated with respect to the base color. -They rely also on the given input parameters such as saturation and luminance. -Those decide how much the colors differ from the base color. - -#+BEGIN_SRC python - def create_colors(base_color): - - 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(-max_hue / 2.0, max_hue / 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) -#+END_SRC - -** Base image - -The base image is a rectangle with the given height and width. -The colors of the edges are the four calculated colors. -All other pixel colors are linear interpolated. - -#+BEGIN_SRC python - # c1 - top left - # c2 - top right - # c3 - bottom right - # c4 - bottom left - def create_base_image(c1, c2, c3, c4): - - # Lambda for adding four colors - add = lambda c1, c2, c3, c4: ( - c1[0] + c2[0] + c3[0] + c4[0], - c1[1] + c2[1] + c3[1] + c4[1], - c1[2] + c2[2] + c3[2] + c4[2], - ) - - # Lambda for multiplying a color with a factor - mul = lambda c, x: (c[0] * x, c[1] * x, c[2] * x) - - # Lambda for scaling a color from [0 , 1] to [0, 255] - cor = lambda c: (int(c[0] * 255), int(c[1] * 255), int(c[2] * 255)) - - # Lambda for calculating a color at x and y in range [0, 1] - # Color limits are set at creation - col = lambda x, y, c1=c1, c2=c2, c3=c3, c4=c4: cor( - add( - mul(c1, (1.0 - x) * (1.0 - y)), - mul(c2, x * (1.0 - y)), - mul(c3, x * y), - mul(c4, (1.0 - x) * y), - ) - ) - - # Create image - image = Image.new("RGBA", (width, height)) - pixels = image.load() - - for x in range(0, width): - for y in range(0, height): - pixels[x, y] = col(x / (width - 1), y / (height - 1)) - - return image -#+END_SRC - -** Lines - -Vertical lines can be added on the side of the huepaper. - -#+BEGIN_SRC python - def add_lines(image, color): - - 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 -#+END_SRC - -** Pixelation - -The huepaper can be pixelated. -This is realized by scaling. - -#+BEGIN_SRC python - def add_pixelation(image, x, y): - - image = image.resize((x, y)) - image = image.resize((width, height), Image.BOX) - - return image -#+END_SRC - -** Emblem - -A huepaper can have an emblem. -This is loaded from a file and placed in the center. - -#+BEGIN_SRC python - def add_emblem(image, filepath): - - # Load image - try: - emblem_image = Image.open(filepath) - except Exception as e: - print("Failed to load emblem: {}".format(e)) - sys.exit(1) - - # Exit if emblem is too big - if emblem_image.size[0] > width or emblem_image.size[1] > height: - print("Emblem can't be bigger than the wallpaper") - sys.exit(1) - - # 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 -#+END_SRC - -** Save - -huepapers can be saved to a filepath. -Already existing files are only overwritten if the user wants to. - -#+BEGIN_SRC python - def save_image(filepath, image): - - 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: " - ) -#+END_SRC - -** Main - -In the main routine, the arguments are parsed and the image is created. - -#+BEGIN_SRC python - def main(): - - global width, height, max_hue, sat_min, sat_max, lum_min, lum_max - - 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="color, the huepaper is generated from (uses a random color if not given)", - ) - parser.add_argument("-p", "--preview", action="store_true", help="preview huepaper") - parser.add_argument( - "-o", "--output", help="file where to save the huepaper to (default: None)" - ) - 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 satisfaction for colors in range [0, 1] (default: 0.2)", - ) - parser.add_argument( - "-smax", - default=1.0, - type=float, - help="maximum satisfaction 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 - preview = args.preview - output = args.output - lines = args.lines - lines_bright = args.lines_bright - lines_dark = args.lines_dark - emblem = args.emblem - pixelate = args.pixelate - max_hue = 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 not preview and not output: - parser.error("You must either set -p (--preview) or -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_logo() - base_color = get_base_color(color) - c1, c2, c3, c4 = create_colors(base_color) - image = create_base_image(c1, c2, c3, c4) - - 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 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(path, image) - - if output: - save_image(output, image) - - - if __name__ == "__main__": - main() -#+END_SRC diff --git a/huepaper.py b/huepaper.py index d0ede72..0900db2 100755 --- a/huepaper.py +++ b/huepaper.py @@ -1,10 +1,12 @@ #!/usr/bin/env python + +from PIL import Image, ImageDraw, ImageOps +from colour import Color import argparse import os.path import random import sys -from colour import Color -from PIL import Image, ImageDraw, ImageOps + def print_logo(): logo = """ @@ -21,8 +23,11 @@ def print_logo(): """ print(logo) + def get_base_color(color_string=None): + global sat_min, sat_max, lum_min, lum_max + # If no color string is given, create a random color if not color_string: hue = random.uniform(0, 1) @@ -41,8 +46,11 @@ def get_base_color(color_string=None): return base_color + def create_colors(base_color): + global max_hue, sat_min, sat_max, lum_min, lum_max + colors = [] max_sat_diff = 0.1 @@ -66,12 +74,15 @@ def create_colors(base_color): return tuple(colors) + # c1 - top left # c2 - top right # c3 - bottom right # c4 - bottom left def create_base_image(c1, c2, c3, c4): + global width, height + # Lambda for adding four colors add = lambda c1, c2, c3, c4: ( c1[0] + c2[0] + c3[0] + c4[0], @@ -106,8 +117,11 @@ def create_base_image(c1, c2, c3, c4): return image + def add_lines(image, color): + global width, height + line_image = Image.new("RGBA", (width, height), (0, 0, 0, 0)) draw = ImageDraw.Draw(line_image) @@ -139,15 +153,21 @@ def add_lines(image, color): return image + def add_pixelation(image, x, y): + global width, height + image = image.resize((x, y)) image = image.resize((width, height), Image.BOX) return image + def add_emblem(image, filepath): + global width, height + # Load image try: emblem_image = Image.open(filepath) @@ -169,6 +189,7 @@ def add_emblem(image, filepath): return image + def save_image(filepath, image): save = True @@ -200,7 +221,8 @@ def save_image(filepath, image): "Please enter new path where the wallpaper shall be saved: " ) -def main(): + +if __name__ == "__main__": global width, height, max_hue, sat_min, sat_max, lum_min, lum_max @@ -353,7 +375,3 @@ def main(): if output: save_image(output, image) - - -if __name__ == "__main__": - main()