"""Иконки приложения — тот же значок, что у сайта pptaxi.ru. Сайт отдаёт `favicon.svg`: красная скруглённая плитка --s-accent и белая «П». Повторяем её здесь, чтобы значок в браузере, на экране телефона и на сайте был один и тот же. Рисуем сами (Pillow), потому что тянуть растеризатор SVG ради одной плитки с буквой незачем. Сглаживание — сверхдискретизацией ×4. Запуск (нужен Pillow): python scripts/gen-icons.py """ from pathlib import Path from PIL import Image, ImageDraw, ImageFont OUT = Path(__file__).resolve().parent.parent / "public" / "icons" ACCENT = (220, 38, 38, 255) # --s-accent сайта PAPER = (255, 255, 255, 255) # --s-paper SS = 4 # Шрифт ищем среди системных: у сайта заголовки набраны Manrope, но ради одной # буквы тащить файл шрифта в репозиторий не стоит — берём ближайший гротеск. FONT_CANDIDATES = [ r"C:\Windows\Fonts\segoeuib.ttf", r"C:\Windows\Fonts\arialbd.ttf", "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", ] def _font(size: int) -> ImageFont.FreeTypeFont: for path in FONT_CANDIDATES: if Path(path).exists(): return ImageFont.truetype(path, size) raise SystemExit("не нашёл жирный шрифт для буквы") def compose(size: int, inset: float, radius_ratio: float = 0.22) -> Image.Image: """inset — доля стороны под плитку. У maskable она меньше: Android режет иконку по кругу, и плитка без запаса теряет углы.""" big = size * SS img = Image.new("RGBA", (big, big), PAPER) draw = ImageDraw.Draw(img) pad = big * (1 - inset) / 2 box = (pad, pad, big - pad, big - pad) draw.rounded_rectangle(box, radius=(box[2] - box[0]) * radius_ratio, fill=ACCENT) letter = "П" font = _font(int((box[3] - box[1]) * 0.72)) l, t, r, b = draw.textbbox((0, 0), letter, font=font) draw.text(((box[0] + box[2] - (r - l)) / 2 - l, (box[1] + box[3] - (b - t)) / 2 - t), letter, font=font, fill=PAPER) return img.resize((size, size), Image.LANCZOS) if __name__ == "__main__": OUT.mkdir(parents=True, exist_ok=True) for name, size, inset in (("icon-192.png", 192, 1.0), ("icon-512.png", 512, 1.0), ("icon-maskable-512.png", 512, 0.72), ("apple-touch-icon.png", 180, 1.0)): compose(size, inset).save(OUT / name) print("собрано", name)