Ctrl K
ComunidadGuías…

scripts/enlarge_brand_icons.py

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env python3
"""Generate web, desktop and Android branding from branding/aoede.png."""

from pathlib import Path

from PIL import Image, ImageChops, ImageOps

ROOT = Path(__file__).resolve().parents[1]
WEB = ROOT / "Aoede/assets" if (ROOT / "Aoede").is_dir() else ROOT / "frontend-source/assets"
ANDROID = ROOT / "android/app/src/main/res" if (ROOT / "android").is_dir() else ROOT / "app/src/main/res"


def main():
    source = Image.open(ROOT / "branding/aoede.png").convert("RGBA")
    bounds = source.getchannel("A").point(lambda alpha: 255 if alpha > 32 else 0).getbbox()
    if bounds is None:
        raise ValueError("The Aoede master icon is empty")
    source = source.crop(bounds)

    def render(size, box, artwork=source):
        left, top, right, bottom = box
        scaled = ImageOps.contain(artwork, (right - left, bottom - top), Image.Resampling.LANCZOS)
        icon = Image.new("RGBA", (size, size))
        icon.alpha_composite(
            scaled, (left + (right - left - scaled.width) // 2, top + (bottom - top - scaled.height) // 2)
        )
        return icon

    # Keep the existing pixel sizes, visual bounds and alignment in each client.
    render(1254, (118, 110, 1137, 1091)).save(WEB / "icon.png", optimize=True)
    desktop = ROOT / "desktop/resources/icons/appIcon.png"
    if desktop.parent.is_dir():
        render(1024, (96, 90, 928, 891)).save(desktop, optimize=True)
    icons = {}
    for size in (16, 32, 48, 64, 128, 180, 192, 256, 512, 1024):
        side = min(size - 2, round(size * 0.92))
        margin = (size - side) // 2
        icons[size] = render(size, (margin, margin, margin + side, margin + side))
    for size in (16, 32):
        icons[size].save(WEB / f"favicon-{size}x{size}.png", optimize=True)
    icons[256].save(
        WEB / "favicon.ico",
        sizes=[(s, s) for s in (16, 32, 48, 64, 128, 256)],
        append_images=[icons[s] for s in (16, 32, 48, 64, 128)],
    )
    for size in (192, 512):
        icons[size].save(WEB / f"android-chrome-{size}x{size}.png", optimize=True)
    # Safari Add to Dock needs a high-resolution, opaque maskable icon. Its
    # background reaches every edge; the colored mark stays in the safe zone.
    for size, name in ((180, "apple-touch-icon.png"), (1024, "app-icon-maskable-1024.png")):
        opaque = Image.new("RGBA", (size, size), "#181b2a")
        opaque.alpha_composite(icons[size])
        opaque.convert("RGB").save(WEB / name, optimize=True)

    # The supplied silver A/waveform is brighter than its dark glass tile.
    # Extract it for Android's flat, system-tinted notification and themed icons.
    mask = ImageChops.multiply(
        ImageOps.grayscale(source).point(lambda value: 255 if value > 160 else 0), source.getchannel("A")
    )
    mark = Image.new("RGBA", source.size, "white")
    mark.putalpha(mask)
    if mask.getbbox() is None:
        raise ValueError("The Aoede monochrome mark is empty")
    notification = mark.crop(mask.getbbox())
    resources = ANDROID
    densities = (
        ("mdpi", 48, (6, 6, 42, 40), 24),
        ("hdpi", 72, (10, 9, 62, 60), 36),
        ("xhdpi", 96, (13, 12, 83, 80), 48),
        ("xxhdpi", 144, (20, 19, 124, 120), 72),
        ("xxxhdpi", 192, (26, 25, 166, 159), 96),
    )
    for density, size, box, small in densities:
        folder = resources / f"mipmap-{density}"
        icon = render(size, box)
        for name in ("ic_launcher", "ic_launcher_round", "ic_launcher_foreground"):
            icon.save(folder / f"{name}.png", optimize=True)
        render(size, box, mark).save(folder / "ic_launcher_monochrome.png", optimize=True)
        folder = resources / f"drawable-{density}"
        folder.mkdir(exist_ok=True)
        inset = small // 8
        render(small, (inset, inset, small - inset, small - inset), notification).save(
            folder / "ic_notification.png", optimize=True
        )


if __name__ == "__main__":
    main()