feat: serve platform logos as 80 px webp
Shown at 40 px, the 96 px PNG logos were 136 KiB of the home page. WebP at twice the display size is 27 KiB for the twelve raster marks. SVG stays as each project publishes it.
No files matched your search
|
Before Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
@@ -2,7 +2,7 @@
|
||||
"note": "Each platform's own logo, owned by its project and shown only to name that platform. Copied once by scripts/fetch_site_images.py.",
|
||||
"images": [
|
||||
{
|
||||
"file": "amberelec.png",
|
||||
"file": "amberelec.webp",
|
||||
"platform": "amberelec",
|
||||
"source": "https://avatars.githubusercontent.com/u/102820909",
|
||||
"owner": "AmberELEC",
|
||||
@@ -16,28 +16,28 @@
|
||||
"licence": "repository licence MIT"
|
||||
},
|
||||
{
|
||||
"file": "bizhawk.png",
|
||||
"file": "bizhawk.webp",
|
||||
"platform": "bizhawk",
|
||||
"source": "https://avatars.githubusercontent.com/u/11743303",
|
||||
"owner": "TASVideos",
|
||||
"licence": "GitHub organisation avatar of TASEmulators"
|
||||
},
|
||||
{
|
||||
"file": "emudeck.png",
|
||||
"file": "emudeck.webp",
|
||||
"platform": "emudeck",
|
||||
"source": "https://raw.githubusercontent.com/dragoonDorise/EmuDeck/main/icons/EmuDeck.png",
|
||||
"owner": "EmuDeck",
|
||||
"licence": "repository licence GPL-3.0"
|
||||
},
|
||||
{
|
||||
"file": "emuelec.png",
|
||||
"file": "emuelec.webp",
|
||||
"platform": "emuelec",
|
||||
"source": "https://avatars.githubusercontent.com/u/57574835",
|
||||
"owner": "EmuELEC",
|
||||
"licence": "GitHub organisation avatar of EmuELEC"
|
||||
},
|
||||
{
|
||||
"file": "knulli.png",
|
||||
"file": "knulli.webp",
|
||||
"platform": "knulli",
|
||||
"source": "https://avatars.githubusercontent.com/u/166268572",
|
||||
"owner": "KNULLI",
|
||||
@@ -51,21 +51,21 @@
|
||||
"licence": "file from libretro/retroarch-assets, CC-BY-4.0"
|
||||
},
|
||||
{
|
||||
"file": "minui.png",
|
||||
"file": "minui.webp",
|
||||
"platform": "minui",
|
||||
"source": "https://avatars.githubusercontent.com/u/225589",
|
||||
"owner": "Shaun Inman",
|
||||
"licence": "GitHub avatar of shauninman, the author of MinUI"
|
||||
},
|
||||
{
|
||||
"file": "misterfpga.png",
|
||||
"file": "misterfpga.webp",
|
||||
"platform": "misterfpga",
|
||||
"source": "https://avatars.githubusercontent.com/u/29345272",
|
||||
"owner": "MiSTer FPGA",
|
||||
"licence": "GitHub organisation avatar of MiSTer-devel"
|
||||
},
|
||||
{
|
||||
"file": "nextui.png",
|
||||
"file": "nextui.webp",
|
||||
"platform": "nextui",
|
||||
"source": "https://avatars.githubusercontent.com/u/202386615",
|
||||
"owner": "LoveRetro",
|
||||
@@ -86,7 +86,7 @@
|
||||
"licence": "repository licence GPL-3.0"
|
||||
},
|
||||
{
|
||||
"file": "retrobat.png",
|
||||
"file": "retrobat.webp",
|
||||
"platform": "retrobat",
|
||||
"source": "https://raw.githubusercontent.com/RetroBat-Official/retrobat/main/system/resources/retrobat_logo_notext.png",
|
||||
"owner": "RetroBat",
|
||||
@@ -100,21 +100,21 @@
|
||||
"licence": "repository licence GPL-3.0"
|
||||
},
|
||||
{
|
||||
"file": "retropie.png",
|
||||
"file": "retropie.webp",
|
||||
"platform": "retropie",
|
||||
"source": "https://avatars.githubusercontent.com/u/11378204",
|
||||
"owner": "RetroPie",
|
||||
"licence": "GitHub organisation avatar of RetroPie"
|
||||
},
|
||||
{
|
||||
"file": "rocknix.png",
|
||||
"file": "rocknix.webp",
|
||||
"platform": "rocknix",
|
||||
"source": "https://avatars.githubusercontent.com/u/163176886",
|
||||
"owner": "ROCKNIX",
|
||||
"licence": "GitHub organisation avatar of ROCKNIX"
|
||||
},
|
||||
{
|
||||
"file": "romm.png",
|
||||
"file": "romm.webp",
|
||||
"platform": "romm",
|
||||
"source": "https://avatars.githubusercontent.com/u/164058018",
|
||||
"owner": "RomM",
|
||||
|
||||
@@ -8,8 +8,9 @@ into ``docs_assets/logos/`` and ``docs_assets/system-icons/``, which are
|
||||
committed, and records where each came from in a ``sources.json`` beside
|
||||
them. The site build only reads those copies (``sitediagrams.localize_images``).
|
||||
|
||||
Raster images are normalised to a square PNG (96 px for logos, 48 px for
|
||||
system icons) so every tile has the same weight, and SVG is kept as published.
|
||||
Raster logos are normalised to an 80 px square WebP, twice the 40 px they
|
||||
are shown at, and system icons to a 48 px PNG, so every tile has the same
|
||||
weight. SVG is kept as published.
|
||||
Normalising needs Pillow. This is a maintenance tool run by hand when a
|
||||
logo changes, not a build step: the build stays on the standard library
|
||||
and PyYAML.
|
||||
@@ -36,7 +37,7 @@ sys.path.insert(0, str(ROOT / "scripts"))
|
||||
|
||||
LOGO_DIR = ROOT / "docs_assets" / "logos"
|
||||
ICON_DIR = ROOT / "docs_assets" / "system-icons"
|
||||
LOGO_SIZE = 96
|
||||
LOGO_SIZE = 80
|
||||
ICON_SIZE = 48
|
||||
AVATAR_HOST = "avatars.githubusercontent.com"
|
||||
USER_AGENT = "retrobios-site-images"
|
||||
@@ -47,7 +48,7 @@ def fetch(url: str) -> bytes:
|
||||
return response.read()
|
||||
|
||||
|
||||
def square_png(data: bytes, size: int) -> bytes:
|
||||
def square_image(data: bytes, size: int, kind: str = "PNG") -> bytes:
|
||||
try:
|
||||
from PIL import Image
|
||||
except ImportError as exc:
|
||||
@@ -57,7 +58,11 @@ def square_png(data: bytes, size: int) -> bytes:
|
||||
tile = Image.new("RGBA", (size, size), (0, 0, 0, 0))
|
||||
tile.paste(image, ((size - image.width) // 2, (size - image.height) // 2), image)
|
||||
out = io.BytesIO()
|
||||
tile.save(out, "PNG", optimize=True)
|
||||
if kind == "WEBP":
|
||||
# Quality 90: half the bytes of lossless, edges still clean at 40 px.
|
||||
tile.save(out, "WEBP", quality=90, method=6)
|
||||
else:
|
||||
tile.save(out, "PNG", optimize=True)
|
||||
return out.getvalue()
|
||||
|
||||
|
||||
@@ -98,7 +103,7 @@ def fetch_logos() -> None:
|
||||
if is_svg(data):
|
||||
file_name, payload = f"{name}.svg", safe_svg(data, url)
|
||||
else:
|
||||
file_name, payload = f"{name}.png", square_png(data, LOGO_SIZE)
|
||||
file_name, payload = f"{name}.webp", square_image(data, LOGO_SIZE, "WEBP")
|
||||
for stale in LOGO_DIR.glob(f"{name}.*"):
|
||||
if stale.name != file_name:
|
||||
stale.unlink()
|
||||
@@ -141,7 +146,7 @@ def fetch_icons() -> None:
|
||||
continue
|
||||
raise
|
||||
file_name = f"{name}.png"
|
||||
(ICON_DIR / file_name).write_bytes(square_png(data, ICON_SIZE))
|
||||
(ICON_DIR / file_name).write_bytes(square_image(data, ICON_SIZE))
|
||||
entries.append({"file": file_name, "source": url})
|
||||
print(f" {file_name}")
|
||||
write_manifest(
|
||||
|
||||