Ce script Python 3 (il nécessite Pillow) prend l'icône maîtresse et, en option, le PNG du symbole seul. Il écrit une icône iOS opaque de 1024 px, l'icône Play de 512 px, les trois PNG de lancement pour chaque densité Android avec le symbole dans la zone de sécurité adaptative, et un splash.gif carré. Exécutez-le en local, ou importez le script et vos images dans ChatGPT et demandez-lui de l'exécuter si l'exécution de code est disponible dans votre offre.
#!/usr/bin/env python3
"""Turn one AI-generated master icon into the files a WebViewGold project needs.
Usage:
python3 make_store_icons.py master.png --bg "#0F766E"
python3 make_store_icons.py master.png --fg symbol.png --bg "#0F766E"
master.png square artwork with a solid, full-bleed background
--fg optional: the symbol alone on a transparent background (better adaptive icon)
--bg the background color of your icon; reuse it as the splash screen color
Requires Pillow: pip install Pillow
"""
import argparse
import math
from pathlib import Path
from PIL import Image, ImageDraw
DENSITIES = {"mdpi": 1, "hdpi": 1.5, "xhdpi": 2, "xxhdpi": 3, "xxxhdpi": 4}
OUT = Path("store-icons")
def flatten(img, bg):
"""Composite on a solid color and drop the alpha channel (App Store requirement)."""
img = img.convert("RGBA")
base = Image.new("RGBA", img.size, bg)
base.alpha_composite(img)
return base.convert("RGB")
def square(img):
w, h = img.size
if w != h:
print(f"warning: master is {w}x{h}, cropping to a centered square")
s = min(w, h)
img = img.crop(((w - s) // 2, (h - s) // 2, (w + s) // 2, (h + s) // 2))
return img
def save(img, path):
path.parent.mkdir(parents=True, exist_ok=True)
img.save(path)
print("wrote", path, img.size, img.mode)
def adaptive_foreground(symbol, px):
"""108 dp canvas; the bounding box of the symbol must fit the 66 dp safe circle."""
canvas = Image.new("RGBA", (px, px), (0, 0, 0, 0))
sym = symbol.convert("RGBA")
sym = sym.crop(sym.getbbox() or (0, 0, sym.width, sym.height))
scale = (px * 66 / 108) / math.hypot(sym.width, sym.height)
sym = sym.resize((max(1, round(sym.width * scale)), max(1, round(sym.height * scale))), Image.LANCZOS)
canvas.alpha_composite(sym, ((px - sym.width) // 2, (px - sym.height) // 2))
return canvas
def main():
ap = argparse.ArgumentParser()
ap.add_argument("master")
ap.add_argument("--fg", help="symbol on a transparent background")
ap.add_argument("--bg", default="#FFFFFF")
a = ap.parse_args()
master = flatten(square(Image.open(a.master)), a.bg)
if master.width < 1024:
print(f"warning: master is only {master.width}px; the App Store needs 1024x1024")
# iOS: one opaque 1024 px PNG for the AppIcon set
save(master.resize((1024, 1024), Image.LANCZOS), OUT / "ios" / "AppIcon-1024.png")
# Google Play listing icon: uploaded in the Play Console, not in the project
save(master.resize((512, 512), Image.LANCZOS), OUT / "play" / "play-icon-512.png")
symbol = Image.open(a.fg) if a.fg else None
for name, f in DENSITIES.items():
folder = OUT / "android" / f"mipmap-{name}"
legacy = round(48 * f)
icon = master.resize((legacy, legacy), Image.LANCZOS)
save(icon, folder / "ic_launcher.png")
mask = Image.new("L", (legacy, legacy), 0)
ImageDraw.Draw(mask).ellipse((0, 0, legacy - 1, legacy - 1), fill=255)
rnd = icon.convert("RGBA")
rnd.putalpha(mask)
save(rnd, folder / "ic_launcher_round.png")
fg_px = round(108 * f)
fg = adaptive_foreground(symbol, fg_px) if symbol else master.resize((fg_px, fg_px), Image.LANCZOS)
save(fg, folder / "ic_launcher_foreground.png")
# Splash: square GIF with the symbol on your splash background color
if symbol:
splash = Image.new("RGB", (1024, 1024), a.bg)
s = adaptive_foreground(symbol, 1024)
splash.paste(s, (0, 0), s)
else:
splash = master.resize((1024, 1024), Image.LANCZOS)
save(splash.convert("P", palette=Image.ADAPTIVE), OUT / "splash" / "splash.gif")
if __name__ == "__main__":
main()