67b3fd23d1
gates / gates (push) Failing after 13m1s
Part A: claim table documentation/audits/website-refresh-2026-10-08/claims.md; "100% open source" corrected from the licence read; unbacked claims cut (firewall, RAID, snapshots, new-machine restore, self-managed mode, household VPN, "never lost"). Part B: dawarich, docmost, grimmory, homebox, karakeep, mealie, metube, radicale, recipe-importer, sparkyfitness cards; plant-it and wger cut (not offered). Part C: /en/ twins, nav language switch, hreflang both ways, sitemap with xhtml:link, og-image-en.png. Part D: site_gates.py twins/lang/same-apps/no-Hungarian/FAQ-JSON-LD/tail. Operator ruling 9 + choice B in 10-localisation.md §11, §10.7. Register: R-902 (contact mailer source in no repo); R-813, R-784, R-559 annotated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
47 lines
2.3 KiB
Python
47 lines
2.3 KiB
Python
"""og-image-en.png: the English twin of og-image.png (1200x630). The Hungarian text areas are repainted from the card's
|
|
own radial background profile, then the English text is drawn in the site's own font (Plus Jakarta Sans, vendored)."""
|
|
import math, sys
|
|
from PIL import Image, ImageDraw, ImageFont, ImageFilter
|
|
A = "/mnt/5_hdd/felhom.eu/git/felhom.eu/website/assets/"
|
|
im = Image.open(A + "og-image.png").convert("RGB")
|
|
W_, H_ = im.size
|
|
px = im.load()
|
|
boxes = [(60, 190, 760, 370), (60, 380, 1060, 470), (60, 505, 460, 580)] # headline, subtitle, button + url
|
|
def inbox(x, y): return any(a <= x <= c and b <= y <= d for a, b, c, d in boxes)
|
|
blur = im.filter(ImageFilter.GaussianBlur(25))
|
|
cx, cy, best = 0, 0, -1
|
|
for y in range(100, 400, 4):
|
|
for x in range(700, 1199, 4):
|
|
r, g, b = blur.getpixel((x, y))
|
|
if b > best: best, cx, cy = b, x, y
|
|
prof = {}
|
|
for y in range(8, H_):
|
|
for x in range(0, W_, 2):
|
|
if inbox(x, y) or (x < 450 and y < 160): continue
|
|
r = int(math.hypot(x - cx, y - cy))
|
|
prof.setdefault(r, []).append(px[x, y])
|
|
med = {}
|
|
for r, v in prof.items():
|
|
v.sort(key=lambda t: t[2]); med[r] = v[len(v) // 2]
|
|
def at(r):
|
|
while r not in med and r > 0: r -= 1
|
|
return med.get(r, (10, 18, 32))
|
|
for a, b, c, d in boxes:
|
|
for y in range(b, d + 1):
|
|
for x in range(a, c + 1):
|
|
px[x, y] = at(int(math.hypot(x - cx, y - cy)))
|
|
dr = ImageDraw.Draw(im)
|
|
def font(size, wght):
|
|
f = ImageFont.truetype(A + "fonts/pjs-latin.woff2", size); f.set_variation_by_axes([wght]); return f
|
|
h = font(78, 800); sub = font(27, 400); btn = font(23, 700); url = font(23, 700)
|
|
dr.text((72, 196), "Your own cloud,", font=h, fill=(237, 242, 249))
|
|
dr.text((72, 280), "your own rules", font=h, fill=(46, 168, 245))
|
|
dr.text((72, 388), "A home server in your own home in Hungary: photos, documents,", font=sub, fill=(148, 166, 191))
|
|
dr.text((72, 426), "media — with automatic backups and a recovery code only you know.", font=sub, fill=(148, 166, 191))
|
|
tw = dr.textlength("Closed test starting", font=btn)
|
|
dr.rectangle((72, 517, 72 + tw + 44, 566), fill=(46, 168, 245))
|
|
dr.text((94, 528), "Closed test starting", font=btn, fill=(10, 18, 32))
|
|
dr.text((72 + tw + 44 + 22, 528), "felhom.eu", font=url, fill=(94, 115, 146))
|
|
im.save(A + "og-image-en.png", optimize=True)
|
|
print("glow centre", cx, cy, "written og-image-en.png")
|