#!/usr/bin/env python3 # Generate the install-window background for the Eleven DMG. # Renders at 2x (retina) then downsamples for the 1x rep, so both are crisp. import os from PIL import Image, ImageDraw, ImageFont OUT = os.path.dirname(os.path.abspath(__file__)) S = 2 # supersample / retina factor W, H = 640 * S, 400 * S # Purple sampled from the app icon (AppIcon icon_1024, core of the violet # gradient) so the "Eleven" wordmark matches the logo exactly. PURPLE = (101, 64, 208) # #6540D0 — wordmark GREY = (150, 155, 168) # the count numbers — light grey, regular weight DOT_GREY = (200, 203, 214) # faint separators / arrow-lighter DARK = (28, 30, 42) MUTED = (122, 126, 140) GRAD_TOP = (252, 252, 255) GRAD_BOT = (235, 237, 249) def font(size, bold=False): size = int(size * S) # Prefer SF Pro (variable font — pick the Bold instance); fall back to Arial. try: f = ImageFont.truetype("/System/Library/Fonts/SFNS.ttf", size) if bold: try: f.set_variation_by_name("Bold") except Exception: pass return f except Exception: p = "/System/Library/Fonts/Supplemental/Arial Bold.ttf" if bold \ else "/System/Library/Fonts/Supplemental/Arial.ttf" return ImageFont.truetype(p, size) # --- base gradient --- img = Image.new("RGB", (W, H), GRAD_TOP) d = ImageDraw.Draw(img) for y in range(H): t = y / (H - 1) d.line([(0, y), (W, y)], fill=tuple( int(a + (b - a) * t) for a, b in zip(GRAD_TOP, GRAD_BOT))) d = ImageDraw.Draw(img) # --- the count: 1 · 2 · … · 10 → (light grey, regular, on the icon line) --- row_y = 208 * S num_font = font(14.5) # match the "Drag the app…" subtitle — one body size arrow_font = num_font # the → is the same size as the numbers (no size-mixing) inter = 2 * S # tight spacing between tokens arrow_gap = 7 * S # a little breathing room before the arrow parts = [] # (text, font, colour) for i in range(1, 11): parts.append((str(i), num_font, GREY)) if i < 10: parts.append(("·", num_font, DOT_GREY)) widths = [d.textlength(t, font=f) for (t, f, _) in parts] arrow_w = d.textlength("→", font=arrow_font) total = sum(widths) + inter * (len(parts) - 1) + arrow_gap + arrow_w x = W / 2 - total / 2 for (t, f, c), w in zip(parts, widths): d.text((x, row_y), t, font=f, fill=c, anchor="lm") x += w + inter x = x - inter + arrow_gap d.text((x, row_y), "→", font=arrow_font, fill=GREY, anchor="lm") # --- title --- title_r = font(27, bold=True) ty = 62 * S seg1, seg2 = "Install ", "Eleven" w1 = d.textlength(seg1, font=title_r) w2 = d.textlength(seg2, font=title_r) sx = (W - (w1 + w2)) / 2 d.text((sx, ty), seg1, font=title_r, fill=DARK, anchor="lm") d.text((sx + w1, ty), seg2, font=title_r, fill=PURPLE, anchor="lm") # --- subtitle --- sub = font(14.5) d.text((W / 2, 98 * S), "Drag the app into your Applications folder", font=sub, fill=MUTED, anchor="mm") img.save(os.path.join(OUT, "background@2x.png")) img.resize((W // S, H // S), Image.LANCZOS).save(os.path.join(OUT, "background.png")) print("wrote background.png (%dx%d) + background@2x.png (%dx%d)" % (W // S, H // S, W, H))