Merge branch 'development' of helene.linode:/mnt/repos/books.alexwlchan.net into...
[books.alexwlchan.net] / scripts / generate_bookshelf.py
1 #!/usr/bin/env python3
2
3 import base64
4 import colorsys
5 import functools
6 import io
7 import os
8 import random
9
10 from PIL import Image, ImageDraw
11
12
13 R = random.Random(0)
14
15
16 def get_bins(total_width, min_height, max_height):
17     x_coord = 0
18
19     while x_coord <= total_width:
20         width = R.randint(8, 40)
21         height = R.randint(min_height, max_height)
22
23         yield [(x_coord, 0), (x_coord + width, height)]
24         x_coord += width
25
26
27 @functools.lru_cache()
28 def get_repeatable_bins(**kwargs):
29     """
30     Get a set of bins which is always the same.
31     """
32     return list(get_bins(**kwargs))
33
34
35 def get_tint_colors(tint_color):
36     r, g, b = tint_color
37     h, s, v = colorsys.rgb_to_hsv(r, g, b)
38
39     v = min(v, 0.45)
40
41     while True:
42         new_brightness = R.uniform(max(v * 3 / 4, 0), min(v * 4 / 3, 1))
43         yield colorsys.hsv_to_rgb(h, s, new_brightness)
44
45
46 def create_shelf(tint_color):
47     # Shelves go from 30px to 45px height, then 2x for retina displays
48     bins = get_repeatable_bins(total_width=2000, min_height=60, max_height=90)
49     colors = get_tint_colors(tint_color=tint_color)
50
51     im = Image.new("RGBA", size=(2000, 90))
52
53     draw = ImageDraw.Draw(im)
54
55     for bin_xy, bin_color in zip(bins, colors):
56         r, g, b = bin_color
57         draw.rectangle(bin_xy, (int(r * 255), int(g * 255), int(b * 255)))
58
59     return im
60
61
62 def create_shelf_data_uri(tint_color):
63     r, g, b = tint_color
64
65     if [r, g, b] == [0, 0, 0] or r <= 0.02 and g <= 0.02 and b <= 0.02:
66         tint_color = [0.2, 0.2, 0.2]
67         r, g, b = tint_color
68
69     try:
70         f = open(f"_shelves/{r}_{g}_{b}.png", "rb")
71     except FileNotFoundError:
72         im = create_shelf(tint_color)
73
74         os.makedirs("_shelves", exist_ok=True)
75
76         im.save(f"_shelves/{r}_{g}_{b}.png")
77         f = open(f"_shelves/{r}_{g}_{b}.png", "rb")
78
79     b64_string = base64.b64encode(f.read()).decode("utf8")
80     return f"data:image/png;base64,{b64_string}"
81
82
83 if __name__ == "__main__":
84     im = get_shelf(tint_color=[
85         0.23529411764705882,
86         0.2627450980392157,
87         0.5294117647058824
88     ])
89
90     im.save("static/bookshelf_blue.png")