embeddinggemma-2-coreai / tests /make_test_images.py
iannedev's picture
v1.1-images
80c945e verified
Raw History Blame Contribute Delete
9.81 kB
#!/usr/bin/env python3
# Copyright 2026 Everpaper. Licensed under the Apache License, Version 2.0 (see ../LICENSE).
"""Render the small fictional image set shipped in tests/images/ (Pillow only, no randomness): a bar chart, a phone
login screen, a slide, an invoice, a flow diagram, a sunset scene (JPEG), a red circle, an RGBA icon, a grayscale
letter, a palette chart, plus two edge-size images (7x5 and 1x300 px) that exercise the resampler's upscale and
extreme-aspect paths. All names, companies and numbers are invented.
python3 make_test_images.py [--out images] -> <out>/*.png|jpg + <out>/manifest.json
The output is repeatable on one machine but NOT byte-identical across machines: text is drawn with the first
system font found in FONT_PATHS (or Pillow's built-in font), and glyph rasterization, PNG compression and JPEG
encoding depend on the font files and on the Pillow / FreeType / zlib / libjpeg versions. The shipped files in
tests/images/ are the reference: image-smoke-reference.json and preprocess-cases.json were computed from them, so
regenerate those two fixtures (make_image_smoke_reference.py, make_preprocess_cases.py) if you regenerate the images.
"""
from __future__ import annotations
import argparse
import json
from pathlib import Path
from PIL import Image, ImageDraw, ImageFont
FONT_PATHS = ["/System/Library/Fonts/Helvetica.ttc", "/System/Library/Fonts/Supplemental/Arial.ttf",
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"]
def font(size: int):
for p in FONT_PATHS:
try:
return ImageFont.truetype(p, size)
except OSError:
continue
return ImageFont.load_default()
def chart_bar(w=640, h=400):
im = Image.new("RGB", (w, h), "white")
d = ImageDraw.Draw(im)
d.text((20, 12), "Lumen lamps - units sold per city, Q3", fill="black", font=font(20))
cities = ["Port Avelin", "North Corra", "Westmere", "Lake Tamsin", "Oskaro"]
vals = [412, 263, 538, 190, 347]
cols = ["#4C78A8", "#F58518", "#54A24B", "#E45756", "#72B7B2"]
d.line([(60, h - 50), (w - 20, h - 50)], fill="black", width=2)
d.line([(60, 50), (60, h - 50)], fill="black", width=2)
bw = (w - 100) // len(cities)
for i, (c, v, col) in enumerate(zip(cities, vals, cols)):
x0 = 70 + i * bw
d.rectangle([x0, h - 50 - v * 0.5, x0 + bw - 20, h - 50], fill=col)
d.text((x0, h - 44), c, fill="black", font=font(13))
d.text((x0 + 5, h - 50 - v * 0.5 - 18), str(v), fill="black", font=font(13))
return im
def ui_login(w=390, h=844):
im = Image.new("RGB", (w, h), "#111418")
d = ImageDraw.Draw(im)
d.rounded_rectangle([40, 160, w - 40, 300], 24, fill="#1d2229")
d.text((60, 180), "Welcome back", fill="white", font=font(28))
d.text((60, 230), "Sign in to Tidal Boards", fill="#9aa4b1", font=font(16))
for i, label in enumerate(["Email", "Password"]):
y = 340 + i * 90
d.rounded_rectangle([40, y, w - 40, y + 56], 14, fill="#1d2229", outline="#2f3842")
d.text((56, y + 18), label, fill="#6b7682", font=font(16))
d.rounded_rectangle([40, 540, w - 40, 596], 14, fill="#2f6fed")
d.text((150, 556), "Sign in", fill="white", font=font(18))
d.text((110, 620), "Forgot your password?", fill="#9aa4b1", font=font(14))
return im
def slide(w=1280, h=720):
im = Image.new("RGB", (w, h), "#f6f3ec")
d = ImageDraw.Draw(im)
d.rectangle([0, 0, w, 90], fill="#264653")
d.text((50, 25), "Nimbus tents: 2027 launch plan", fill="white", font=font(36))
bullets = ["Three sizes, one pole system", "Pre-orders open in March", "Retail partners in six cities",
"Target: 18,000 units in the first season"]
for i, b in enumerate(bullets):
d.ellipse([70, 160 + i * 90, 90, 180 + i * 90], fill="#2a9d8f")
d.text((110, 150 + i * 90), b, fill="#222", font=font(30))
d.text((w - 260, h - 50), "slide 4 of 12", fill="#777", font=font(18))
return im
def doc_invoice(w=595, h=842):
im = Image.new("RGB", (w, h), "white")
d = ImageDraw.Draw(im)
d.text((40, 40), "INVOICE No. 2027-0418", fill="black", font=font(22))
d.text((40, 80), "Quill Pens Ltd., 12 Harbour Lane, Port Avelin", fill="black", font=font(13))
d.text((40, 100), "Bill to: Westmere Public Library", fill="black", font=font(13))
y = 160
d.line([(40, y), (w - 40, y)], fill="black")
rows = [("Fountain pen, steel nib", 24, "18.00"), ("Ink cartridges (box of 50)", 6, "9.50"), ("Gift boxes", 24, "2.20"),
("Shipping", 1, "14.00")]
for name, qty, price in rows:
y += 30
d.text((40, y), name, fill="black", font=font(13))
d.text((380, y), str(qty), fill="black", font=font(13))
d.text((460, y), price, fill="black", font=font(13))
y += 50
d.line([(40, y), (w - 40, y)], fill="black")
d.text((380, y + 15), "Total: 555.80", fill="black", font=font(15))
d.text((40, h - 80), "Payment within 30 days. Thank you for your order.", fill="black", font=font(12))
return im
def diagram_flow(w=800, h=500):
im = Image.new("RGB", (w, h), "white")
d = ImageDraw.Draw(im)
boxes = [("Order received", 60, 200), ("Check stock", 300, 200), ("Pack", 540, 120), ("Back-order", 540, 280)]
for t, x, y in boxes:
d.rounded_rectangle([x, y, x + 180, y + 70], 12, fill="#dbeafe", outline="#1e3a8a", width=2)
d.text((x + 15, y + 25), t, fill="#1e3a8a", font=font(17))
for a, b in [((240, 235), (300, 235)), ((480, 220), (540, 155)), ((480, 250), (540, 315))]:
d.line([a, b], fill="#1e3a8a", width=3)
d.polygon([b, (b[0] - 12, b[1] - 6), (b[0] - 12, b[1] + 6)], fill="#1e3a8a")
d.text((320, 60), "Fulfilment flow", fill="black", font=font(24))
return im
def scene_sunset(w=800, h=533):
im = Image.new("RGB", (w, h))
d = ImageDraw.Draw(im)
for y in range(h):
t = y / h
if t < 0.6:
c = (int(40 + 200 * t / 0.6), int(60 + 90 * t / 0.6), int(120 - 80 * t / 0.6))
else:
c = (int(20 + 30 * (t - 0.6) / 0.4), int(50 + 40 * (t - 0.6) / 0.4), int(90 + 60 * (t - 0.6) / 0.4))
d.line([(0, y), (w, y)], fill=c)
d.ellipse([w // 2 - 60, int(h * 0.6) - 60, w // 2 + 60, int(h * 0.6) + 60], fill="#ffb347")
d.rectangle([0, int(h * 0.6), w, h], fill=None)
for i in range(0, w, 40):
d.line([(i, int(h * 0.62) + (i % 80) // 20), (i + 24, int(h * 0.62) + (i % 80) // 20)], fill="#ffd27f", width=2)
return im
def shape_red_circle(w=300, h=300):
im = Image.new("RGB", (w, h), "white")
ImageDraw.Draw(im).ellipse([50, 50, 250, 250], fill="#d62828")
return im
def icon_rgba(w=256, h=256):
im = Image.new("RGBA", (w, h), (0, 0, 0, 0))
d = ImageDraw.Draw(im)
d.rounded_rectangle([20, 20, 236, 236], 48, fill=(47, 111, 237, 255))
d.polygon([(100, 75), (100, 181), (185, 128)], fill=(255, 255, 255, 255))
return im
def gray_letter(w=600, h=800):
im = Image.new("L", (w, h), 245)
d = ImageDraw.Draw(im)
lines = ["Dear neighbours,", "", "The community garden on Fern Street reopens on the first Saturday of May.",
"Plots are assigned in the order of the sign-up sheet at the library.", "Tools stay in the shed; please",
"return them before dusk.", "", "With thanks, the garden committee"]
for i, l in enumerate(lines):
d.text((50, 60 + i * 32), l, fill=20, font=font(16))
return im
def palette_chart(w=500, h=320):
im = Image.new("RGB", (w, h), "white")
d = ImageDraw.Draw(im)
d.text((20, 10), "Sales channel share", fill="black", font=font(18))
start = 0
for frac, col in [(0.45, "#1b9e77"), (0.3, "#d95f02"), (0.25, "#7570b3")]:
d.pieslice([120, 60, 380, 300], start, start + frac * 360, fill=col)
start += frac * 360
return im.quantize(16)
def build(out: Path) -> list[dict]:
out.mkdir(parents=True, exist_ok=True)
items = []
def save(name, im, query, fmt="PNG", **kw):
fn = f"{name}.{'jpg' if fmt == 'JPEG' else 'png'}"
im.save(out / fn, format=fmt, **kw)
with Image.open(out / fn) as chk:
items.append(dict(name=name, file=fn, query=query, width=chk.width, height=chk.height, mode=chk.mode, lossy=fmt == "JPEG"))
save("chart_bar", chart_bar(), "bar chart of lamp units sold per city")
save("ui_login", ui_login(), "dark mobile login screen with email and password fields")
save("slide_launch", slide(), "presentation slide about a tent product launch plan")
save("doc_invoice", doc_invoice(), "invoice for fountain pens and ink cartridges")
save("diagram_flow", diagram_flow(), "flow diagram of order fulfilment steps")
save("scene_sunset", scene_sunset(), "sunset over the sea with an orange sun", fmt="JPEG", quality=90)
save("shape_red_circle", shape_red_circle(), "a red circle on a white background")
save("icon_rgba", icon_rgba(), "blue rounded app icon with a white play symbol")
save("gray_letter", gray_letter(), "letter about a community garden reopening")
save("palette_chart", palette_chart(), "pie chart of sales channel share")
save("edge_tiny_7x5", shape_red_circle().resize((7, 5), Image.BICUBIC), "a red circle on a white background")
save("edge_strip_1x300", ui_login().resize((1, 300), Image.BICUBIC), "a thin vertical strip")
return items
def main() -> None:
ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
ap.add_argument("--out", default=str(Path(__file__).resolve().parent / "images"))
args = ap.parse_args()
items = build(Path(args.out))
(Path(args.out) / "manifest.json").write_text(json.dumps(items, indent=1) + "\n")
print(len(items), "images ->", args.out)
if __name__ == "__main__":
main()