# Matching app icons

Use a licensed, transparent PNG glyph. Microsoft's public Fluent 3D emoji repository is one option for a generic symbol. For a brand-specific app, obtain permission to use the official mark. The snippet uses Pillow and downloads only public artwork; it does not bundle any images. **Bring your own images** if you don't want to download an emoji.

Copy this fenced code into a local Python file if you want an executable compositor:

```python
import argparse
from io import BytesIO
from pathlib import Path
from urllib.parse import quote
from urllib.request import urlopen

from PIL import Image, ImageDraw, ImageFilter

SIZE = 512
TOP = (250, 250, 248)
BOTTOM = (226, 240, 230)


def load_glyph(emoji: str | None, glyph: str | None) -> Image.Image:
    if bool(emoji) == bool(glyph):
        raise ValueError("Choose exactly one of --emoji or --glyph")
    if glyph:
        return Image.open(glyph).convert("RGBA")
    name = emoji.strip()
    stem = name.lower().replace(" ", "_")
    url = (
        "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/"
        f"{quote(name)}/3D/{stem}_3d.png"
    )
    with urlopen(url, timeout=20) as response:
        return Image.open(BytesIO(response.read())).convert("RGBA")


def make_icon(glyph: Image.Image, output: Path) -> None:
    size = SIZE
    gradient = Image.new("RGB", (size, size))
    draw = ImageDraw.Draw(gradient)
    for y in range(size):
        t = y / (size - 1)
        row = tuple(round(a + (b - a) * t) for a, b in zip(TOP, BOTTOM))
        draw.line((0, y, size, y), fill=row)

    tile_mask = Image.new("L", (size, size), 0)
    ImageDraw.Draw(tile_mask).rounded_rectangle(
        (0, 0, size - 1, size - 1), radius=round(size * .22), fill=255
    )
    tile = Image.new("RGBA", (size, size), (0, 0, 0, 0))
    tile.paste(gradient, (0, 0), tile_mask)
    edge = ImageDraw.Draw(tile)
    edge.rounded_rectangle(
        (2, 2, size - 3, size - 3), radius=round(size * .22),
        outline=(255, 255, 255, 155), width=3
    )

    bounds = glyph.getbbox()
    if bounds is None:
        raise ValueError("The glyph has no visible pixels")
    glyph = glyph.crop(bounds)
    glyph.thumbnail((round(size * .64), round(size * .64)), Image.Resampling.LANCZOS)
    x, y = (size - glyph.width) // 2, (size - glyph.height) // 2

    shadow = Image.new("RGBA", (size, size), (0, 0, 0, 0))
    shadow_color = Image.new("RGBA", glyph.size, (20, 25, 20, 0))
    shadow_color.putalpha(glyph.getchannel("A").point(lambda a: round(a * .30)))
    shadow.alpha_composite(shadow_color, (x, y + round(size * .03)))
    tile = Image.alpha_composite(tile, shadow.filter(ImageFilter.GaussianBlur(11)))
    tile.alpha_composite(glyph, (x, y))

    output.parent.mkdir(parents=True, exist_ok=True)
    tile.save(output, format="PNG")


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    source = parser.add_mutually_exclusive_group(required=True)
    source.add_argument("--emoji", help="Public Fluent 3D emoji name, such as 'Open book'")
    source.add_argument("--glyph", help="Path to a transparent, licensed PNG")
    parser.add_argument("--out", required=True, help="Output path for the 512px PNG")
    args = parser.parse_args()
    make_icon(load_glyph(args.emoji, args.glyph), Path(args.out))
```

Run `python3 your-compositor.py --emoji "Open book" --out public/favicon.png` or pass `--glyph path/to/mark.png`. Check the emoji's exact repository name if its public URL returns 404. Resize and inspect the result at both 512px and favicon size. If Pillow isn't installed in your own environment, install it through your usual package manager; don't assume another user's tooling is present.
