T45 Website: native captures stand in where a browser cannot run, an OG image, no web notes
This commit is contained in:
68 files changed
+315
-155
No files matched your search
@@ -0,0 +1,94 @@
|
||||
"""Writes frontend/public/shots: native captures a browser cannot make."""
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image, ImageChops
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
OUT = ROOT / "frontend/public/shots"
|
||||
GROUND = {"light": (252, 250, 247, 255), "dark": (19, 17, 16, 255)}
|
||||
|
||||
# Stories shown as a capture: their demo needs the desktop.
|
||||
STORIES = [
|
||||
("terminal", "terminal-terminaltabs-terminalsplit-terminaltoolbar-shellselector-terminalsearch-terminallink"),
|
||||
("forms", "fileinput-dropzone"),
|
||||
("forms", "pathinput"),
|
||||
("files", "dragdropfiles"),
|
||||
("theme", "themeimporter-syntaxthemes"),
|
||||
("media", "imageupload"),
|
||||
("shell", "trayicon-traymenu"),
|
||||
("shell", "dockbadge"),
|
||||
("shell", "windowdragregion"),
|
||||
("shell", "windowresizeborder"),
|
||||
]
|
||||
|
||||
# Live stories, and the windows their page scripts open.
|
||||
WINDOWS = {
|
||||
"shell/splashscreen": ["shell-splash-window"],
|
||||
"shell/aboutdialog": ["shell-about-window"],
|
||||
"shell/multiwindow-manager": ["shell-managed-window"],
|
||||
"shell/miniwindow-compactmode-pictureinpicture": ["shell-mini-window", "shell-pip-window"],
|
||||
"shell/updatedialog": ["shell-update-window"],
|
||||
"shell/crashreporter": ["shell-crash-window"],
|
||||
"navigation/searchpalette-spotlightsearch-quicklauncher": ["navigation-launcher"],
|
||||
"theme/platform-style-iconthemeprovider-vibrancybackground": ["theme-frosted-window"],
|
||||
}
|
||||
|
||||
|
||||
def capture(args, into):
|
||||
"""Runs the native capture; its window must stay in front."""
|
||||
subprocess.run(["cargo", "run", "-q", "--example", "gallery", "--", *args, "--capture", str(into)], cwd=ROOT, check=True)
|
||||
|
||||
|
||||
def trimmed(path):
|
||||
"""The shot cut to its content, a margin around it."""
|
||||
im = Image.open(path).convert("RGB")
|
||||
# The title bar and the window's rounded edge stay out.
|
||||
edge, bar = 16, 112
|
||||
inner = im.crop((edge, bar, im.width - edge, im.height - edge))
|
||||
ground = Image.new("RGB", inner.size, inner.getpixel((inner.width // 2, inner.height - 8)))
|
||||
box = ImageChops.difference(inner, ground).convert("L").point(lambda v: 255 if v > 24 else 0).getbbox()
|
||||
if box is None:
|
||||
sys.exit(f"shots.py: {path} is blank")
|
||||
box = (box[0] + edge, box[1] + bar, box[2] + edge, box[3] + bar)
|
||||
pad = 48
|
||||
return im.crop((max(box[0] - pad, 0), max(box[1] - pad, 0), min(box[2] + pad, im.width), min(box[3] + pad, im.height)))
|
||||
|
||||
|
||||
def grounded(path, mode):
|
||||
"""A window's capture over the site's ground, its corners filled."""
|
||||
window = Image.open(path).convert("RGBA")
|
||||
ground = Image.new("RGBA", window.size, GROUND[mode])
|
||||
return Image.alpha_composite(ground, window).convert("RGB")
|
||||
|
||||
|
||||
def save(im, name):
|
||||
im.save(OUT / f"{name}.jpg", quality=88, optimize=True)
|
||||
print(f"shots.py: {name}.jpg {im.width}x{im.height}")
|
||||
|
||||
|
||||
def main():
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
manifest = {"stories": [], "windows": WINDOWS}
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
tmp = Path(tmp)
|
||||
for page, story in STORIES:
|
||||
into = tmp / f"{page}--{story}"
|
||||
capture(["--page", page, "--story", story], into)
|
||||
for mode in ("light", "dark"):
|
||||
save(trimmed(into / f"{page}-{mode}.png"), f"{page}--{story}-{mode}")
|
||||
manifest["stories"].append(f"{page}/{story}")
|
||||
for page in sorted({key.split("/")[0] for key in WINDOWS}):
|
||||
into = tmp / page
|
||||
capture(["--page", page], into)
|
||||
for name in (n for key, names in WINDOWS.items() if key.startswith(page + "/") for n in names):
|
||||
for mode in ("light", "dark"):
|
||||
save(grounded(into / f"{name}-{mode}.png", mode), f"{name}-{mode}")
|
||||
(ROOT / "frontend/src/shots.json").write_text(json.dumps(manifest, indent=1) + "\n")
|
||||
|
||||
|
||||
main()
|
||||
Reference in new issue
Block a user