1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#!/usr/bin/env python3
"""Generate the 1024x500 Play Store feature graphic.
python3 tools/generate_feature_graphic.py
Play crops this differently across surfaces and overlays a play button on some
of them, so the wordmark sits left of centre and well inside the frame rather
than dead centre where the overlay lands.
The wordmark uses Syne ExtraBold, which is --font-display on grain.social.
"""
import os
from PIL import Image, ImageDraw, ImageEnhance, ImageFilter
SOURCE = os.path.expanduser(
"~/code/grain-ios/Grain/Assets.xcassets/AppIcon.appiconset/1024.png"
)
OUT = "store/play-feature-graphic-1024x500.png"
FONT = os.path.join(os.path.dirname(__file__), "fonts", "Syne-ExtraBold.ttf")
WIDTH, HEIGHT = 1024, 500
# Lowercase, as the app and the site set it.
WORDMARK = "grain"
def main() -> None:
src = Image.open(SOURCE).convert("RGB")
# Take a full-width band from the upper half: the ridge line and the dusk
# sky read at this aspect, where the foreground heather turns to mush.
band_height = round(src.width * HEIGHT / WIDTH)
top = round(src.height * 0.22)
band = src.crop((0, top, src.width, top + band_height))
graphic = band.resize((WIDTH, HEIGHT), Image.LANCZOS)
# Darken toward the left so the wordmark holds contrast over whatever
# happens to be behind it.
scrim = Image.new("L", (WIDTH, HEIGHT), 0)
ImageDraw.Draw(scrim).rectangle((0, 0, WIDTH, HEIGHT), fill=110)
scrim = scrim.filter(ImageFilter.GaussianBlur(80))
graphic = Image.composite(
ImageEnhance.Brightness(graphic).enhance(0.55), graphic, scrim
)
from PIL import ImageFont
draw = ImageDraw.Draw(graphic)
title = ImageFont.truetype(FONT, 150)
# Centre on the optical bounds rather than the layout box: "grain" has no
# ascender and one descender, so the font's line metrics would sit it
# visibly high in the frame.
left, top_, right, bottom = draw.textbbox((0, 0), WORDMARK, font=title)
draw.text(
(88 - left, (HEIGHT - (bottom - top_)) / 2 - top_),
WORDMARK,
font=title,
fill=(255, 255, 255),
)
os.makedirs("store", exist_ok=True)
graphic.save(OUT, optimize=True)
print(f"{OUT}: {graphic.size[0]}x{graphic.size[1]}")
if __name__ == "__main__":
main()