"""Regenerate Tauri/desktop icons from heicode-logo.jpg.""" from pathlib import Path from PIL import Image ROOT = Path(__file__).resolve().parent.parent SRC = ROOT / "heicode-logo.jpg" TAURI_ICONS = ROOT / "cc-haha" / "desktop" / "src-tauri" / "icons" PUBLIC = ROOT / "cc-haha" / "desktop" / "public" def load_trimmed_square(): img = Image.open(SRC).convert("RGB") # Find bbox of non-white pixels (treat >=250 RGB as white). gray = img.convert("L") mask = gray.point(lambda v: 0 if v >= 250 else 255) bbox = mask.getbbox() if bbox: img = img.crop(bbox) # Pad to square on white. w, h = img.size side = max(w, h) canvas = Image.new("RGB", (side, side), (255, 255, 255)) canvas.paste(img, ((side - w) // 2, (side - h) // 2)) return canvas def to_rgba_with_transparent_white(img: Image.Image, threshold: int = 248) -> Image.Image: rgba = img.convert("RGBA") pixels = rgba.load() w, h = rgba.size for y in range(h): for x in range(w): r, g, b, _ = pixels[x, y] if r >= threshold and g >= threshold and b >= threshold: pixels[x, y] = (r, g, b, 0) return rgba def main(): base = load_trimmed_square() print(f"Trimmed source: {base.size}") # PNG outputs (RGB on white → looks correct on any background, matches glass edges). sizes = { TAURI_ICONS / "32x32.png": 32, TAURI_ICONS / "64x64.png": 64, TAURI_ICONS / "128x128.png": 128, TAURI_ICONS / "128x128@2x.png": 256, TAURI_ICONS / "icon.png": 1024, PUBLIC / "app-icon.png": 1024, } for path, size in sizes.items(): path.parent.mkdir(parents=True, exist_ok=True) # Tauri's macOS bundler rejects non-RGBA PNGs ("icon ... is not RGBA"). # Force RGBA on every PNG output so the same files work for both # Windows .ico embedding and macOS .icns embedding without per-platform # branches. Alpha channel is fully opaque (255) since we paint on # solid white in load_trimmed_square — the rounded glass edges of the # logo retain their painted look on any background. base.resize((size, size), Image.LANCZOS).convert("RGBA").save(path, "PNG") print(f"wrote {path} ({size})") # Windows Square*Logo / StoreLogo win_sizes = { "Square30x30Logo.png": 30, "Square44x44Logo.png": 44, "Square71x71Logo.png": 71, "Square89x89Logo.png": 89, "Square107x107Logo.png": 107, "Square142x142Logo.png": 142, "Square150x150Logo.png": 150, "Square284x284Logo.png": 284, "Square310x310Logo.png": 310, "StoreLogo.png": 50, } for name, size in win_sizes.items(): path = TAURI_ICONS / name # Tauri's macOS bundler rejects non-RGBA PNGs ("icon ... is not RGBA"). # Force RGBA on every PNG output so the same files work for both # Windows .ico embedding and macOS .icns embedding without per-platform # branches. Alpha channel is fully opaque (255) since we paint on # solid white in load_trimmed_square — the rounded glass edges of the # logo retain their painted look on any background. base.resize((size, size), Image.LANCZOS).convert("RGBA").save(path, "PNG") print(f"wrote {path} ({size})") # ICO with multi-resolution. ico_path = TAURI_ICONS / "icon.ico" base.save(ico_path, format="ICO", sizes=[(16,16),(24,24),(32,32),(48,48),(64,64),(128,128),(256,256)]) print(f"wrote {ico_path}") # ICNS (PIL supports it). Required sizes: 16,32,64,128,256,512,1024. icns_path = TAURI_ICONS / "icon.icns" base.save(icns_path, format="ICNS", sizes=[(16,16),(32,32),(64,64),(128,128),(256,256),(512,512),(1024,1024)]) print(f"wrote {icns_path}") if __name__ == "__main__": main()