|
| 1 | +""" |
| 2 | +generate_icon.py - Creates npcjason.ico from pixel art. |
| 3 | +Produces a proper multi-resolution ICO file (16, 32, 48, 64, 256px). |
| 4 | +Run this before building with PyInstaller. |
| 5 | +""" |
| 6 | + |
| 7 | +from PIL import Image, ImageDraw |
| 8 | + |
| 9 | + |
| 10 | +def make_npcjason_image(size: int) -> Image.Image: |
| 11 | + """Draw the NPCJason pixel art face scaled to the given square size.""" |
| 12 | + img = Image.new("RGBA", (size, size), (0, 0, 0, 0)) |
| 13 | + draw = ImageDraw.Draw(img) |
| 14 | + |
| 15 | + # All coordinates are defined for a 64x64 canvas, then scaled. |
| 16 | + s = size / 64.0 |
| 17 | + |
| 18 | + def r(x1, y1, x2, y2, fill, outline=None, width=1): |
| 19 | + coords = [x1 * s, y1 * s, x2 * s, y2 * s] |
| 20 | + if outline: |
| 21 | + draw.rectangle(coords, fill=fill, outline=outline, width=max(1, int(width * s))) |
| 22 | + else: |
| 23 | + draw.rectangle(coords, fill=fill) |
| 24 | + |
| 25 | + # Hair |
| 26 | + r(14, 4, 50, 16, "#4a3728", "#1a1a2e", 1) |
| 27 | + # Head / skin |
| 28 | + r(16, 8, 48, 40, "#e8c170", "#1a1a2e", 2) |
| 29 | + # Eyes |
| 30 | + r(22, 20, 28, 26, "#16213e") |
| 31 | + r(36, 20, 42, 26, "#16213e") |
| 32 | + # Eye whites (small highlight) |
| 33 | + r(23, 21, 25, 23, "#ffffff") |
| 34 | + r(37, 21, 39, 23, "#ffffff") |
| 35 | + # Mouth / smile |
| 36 | + r(26, 30, 38, 35, "#c84b31") |
| 37 | + # Body / shirt |
| 38 | + r(20, 40, 44, 56, "#3a86c8", "#1a1a2e", 1) |
| 39 | + # Legs / pants |
| 40 | + r(22, 56, 30, 64, "#2d4263") |
| 41 | + r(34, 56, 42, 64, "#2d4263") |
| 42 | + |
| 43 | + return img |
| 44 | + |
| 45 | + |
| 46 | +def generate_ico(output_path: str = "npcjason.ico"): |
| 47 | + sizes = [16, 32, 48, 64, 256] |
| 48 | + images = [make_npcjason_image(s) for s in sizes] |
| 49 | + |
| 50 | + # Save as proper multi-resolution ICO. |
| 51 | + # Pillow uses the first image as the base; sizes kwarg embeds all resolutions. |
| 52 | + images[0].save( |
| 53 | + output_path, |
| 54 | + format="ICO", |
| 55 | + sizes=[(s, s) for s in sizes], |
| 56 | + append_images=images[1:], |
| 57 | + ) |
| 58 | + print(f"Icon saved: {output_path} ({', '.join(str(s) for s in sizes)}px)") |
| 59 | + |
| 60 | + |
| 61 | +if __name__ == "__main__": |
| 62 | + generate_ico() |
0 commit comments