"""Build the app icons from images/mtga-assistant-icon.png (the single source image). Writes: * src/mtga_assistant/icon.png: loaded at runtime for the window, taskbar and tray icon. * images/mtga-assistant-icon.ico: the Windows .exe icon (PNG-compressed entries at the usual sizes). Run after changing the source image: uv run python packaging/make_icon.py """ import shutil import struct import sys from pathlib import Path from PySide6.QtCore import QBuffer, QByteArray, QIODevice, Qt from PySide6.QtGui import QGuiApplication, QImage SIZES = [16, 24, 32, 48, 64, 128, 256] ROOT = Path(__file__).resolve().parent.parent SOURCE = ROOT / "images" / "mtga-assistant-icon.png" def png_at(img: QImage, size: int) -> bytes: scaled = img.scaled(size, size, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation) data = QByteArray() buf = QBuffer(data) buf.open(QIODevice.OpenModeFlag.WriteOnly) scaled.save(buf, "PNG") # type: ignore[arg-type] # PySide accepts str; its stubs say bytes return data.data() def main() -> None: QGuiApplication(sys.argv[:1]) img = QImage(str(SOURCE)) if img.isNull(): sys.exit(f"can't read {SOURCE}") pngs = [(size, png_at(img, size)) for size in SIZES] # ICONDIR header, one ICONDIRENTRY per image, then the PNG data. out = struct.pack("= 256 else size # 0 means 256 out += struct.pack("