chore: initial import — heicode manager + website
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
"""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()
|
||||
Reference in New Issue
Block a user