#!/usr/bin/env python3 """Finish the landing-page cover pair from the flux base image. Stamps the title (so the band name is spelled by us, not by a diffusion model) and derives the risograph hover variant (two-ink duotone, offset plates, paper grain). python3 tools/make_cover.py OUT_DIR """ import os import random import sys from PIL import Image, ImageDraw, ImageEnhance, ImageFont, ImageOps HERE = os.path.dirname(__file__) BASE = os.path.join(HERE, "..", "pics", "cover-blank.png") FONTS = [ "/System/Library/Fonts/Supplemental/Impact.ttf", "/System/Library/Fonts/Supplemental/Arial Black.ttf", "/System/Library/Fonts/Helvetica.ttc", ] def font(size): for f in FONTS: if os.path.exists(f): try: return ImageFont.truetype(f, size) except OSError: continue return ImageFont.load_default() def stamp_title(img): d = ImageDraw.Draw(img) w = img.width def line(text, y, size, fill): f = font(size) tw = d.textlength(text, font=f) x = (w - tw) / 2 # fat xerox outline: many offset passes for dx in range(-4, 5, 2): for dy in range(-4, 5, 2): d.text((x + dx, y + dy), text, font=f, fill=(12, 10, 8)) d.text((x, y), text, font=f, fill=fill) line("NOMEANSNO", 26, 118, (238, 232, 220)) line("QUEST", 148, 96, (208, 40, 32)) return img def riso(img): paper = Image.new("RGB", img.size, (240, 233, 216)) g = ImageOps.autocontrast(img.convert("L")) # ink plates from tone bands dark = g.point(lambda v: 255 if v < 90 else 0) mid = g.point(lambda v: 255 if 90 <= v < 175 else 0) blue = Image.new("RGB", img.size, (36, 62, 168)) red = Image.new("RGB", img.size, (222, 60, 44)) out = paper.copy() # misregistered plates, like a real duplicator on a deadline out.paste(red, (3, 2), mid) out.paste(blue, (0, 0), dark) # grain rng = random.Random(41) px = out.load() for _ in range(img.width * img.height // 14): x = rng.randrange(img.width) y = rng.randrange(img.height) r, gr, b = px[x, y] n = rng.randint(-18, 18) px[x, y] = (max(0, min(255, r + n)), max(0, min(255, gr + n)), max(0, min(255, b + n))) return out def main(): out_dir = sys.argv[1] if len(sys.argv) > 1 else os.path.join(HERE, "..", "covers") os.makedirs(out_dir, exist_ok=True) base = Image.open(BASE).convert("RGB") base = ImageEnhance.Contrast(base).enhance(1.08) titled = stamp_title(base.copy()) cover = ImageOps.fit(titled, (311, 400), Image.LANCZOS) cover.save(os.path.join(out_dir, "nomeansnoquest.jpg"), quality=88) riso_img = ImageOps.fit(riso(stamp_title(base.copy())), (311, 400), Image.LANCZOS) riso_img.save(os.path.join(out_dir, "nomeansnoquest_riso.jpg"), quality=88) print("covers written:", out_dir) if __name__ == "__main__": main()