Files
Ely-GPUI-Components/scripts/captcha.py
T
ZacharyZhang-NY 692fae6244 Misc · Codes and checks: a QR code scanner and a captcha
misc::QrCodeScanner reads QR codes with rqrr 0.11 from the frames the
host hands in, one at a time off the main thread, and hands each code
to the owner once. misc::Captcha shows the owner's picture over an
answer field that empties and keeps focus with each answer; the owner
says how it stood. BarcodeDisplay, Signature and Rating Widget point
to their homes.
2026-09-28 01:40:15 -04:00

46 lines
1.6 KiB
Python

"""Writes the gallery's captcha pictures: each answer's letters turned and set off, over noise.
Usage: python3 scripts/captcha.py
The seed is fixed, so the pictures come out the same each run.
"""
import random
from pathlib import Path
from PIL import Image, ImageDraw, ImageFont
ROOT = Path(__file__).resolve().parent.parent
OUT = ROOT / "examples/gallery/assets/captcha"
FONT = ImageFont.truetype(str(ROOT / "assets/fonts/Inter-SemiBold.ttf"), 76)
ANSWERS = ["W7XK", "Q3NP"]
SIZE = (480, 160)
def picture(answer, rng):
image = Image.new("RGB", SIZE, (236, 238, 242))
draw = ImageDraw.Draw(image)
for _ in range(900):
x, y = rng.randrange(SIZE[0]), rng.randrange(SIZE[1])
draw.point((x, y), fill=tuple(rng.randrange(150, 210) for _ in range(3)))
step = SIZE[0] // (len(answer) + 1)
for ix, letter in enumerate(answer):
tile = Image.new("RGBA", (120, 120), (0, 0, 0, 0))
ImageDraw.Draw(tile).text((60, 60), letter, font=FONT, anchor="mm", fill=(40, 48, 70, 255))
tile = tile.rotate(rng.uniform(-28, 28), resample=Image.BICUBIC)
image.paste(tile, (step * (ix + 1) - 60, 20 + rng.randrange(-14, 14)), tile)
for _ in range(5):
points = [(x, rng.randrange(20, SIZE[1] - 20)) for x in range(0, SIZE[0] + 60, 60)]
draw.line(points, fill=(90, 100, 130), width=3)
return image
def main():
OUT.mkdir(parents=True, exist_ok=True)
rng = random.Random(42)
for answer in ANSWERS:
picture(answer, rng).save(OUT / f"{answer.lower()}.png")
print(f"wrote {answer.lower()}.png")
main()