Use the new app icon

The icon now comes from images/mtga-assistant-icon.png: make_icon.py
copies it into the package (window, taskbar and tray icon) and builds
the Windows .ico used for the .exe. The old generated SVG icon is gone.
The PyInstaller spec also keeps QtNetwork, needed for single-instance.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Aeth3randClaude Opus 5.5 committed 2026-10-19 09:54:08 -04:00
1 parent c4533d12c0
commit fb6220155c
7 files changed
+23 -33

No files matched your search

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

-11
View File
@@ -1,11 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
<rect x="8" y="8" width="240" height="240" rx="56" fill="#14171a"/>
<rect x="8" y="8" width="240" height="240" rx="56" fill="none" stroke="#2f353b" stroke-width="6"/>
<g transform="rotate(-10 128 128)">
<rect x="70" y="44" width="116" height="168" rx="14" fill="#1d2125" stroke="#3eb489" stroke-width="10"/>
<rect x="86" y="62" width="84" height="58" rx="6" fill="#24443a"/>
</g>
<circle cx="98" cy="166" r="13" fill="#c1d7e9"/>
<circle cx="130" cy="160" r="13" fill="#bab1ab"/>
<circle cx="162" cy="154" r="13" fill="#e49977"/>
</svg>

Before

Width:  |  Height:  |  Size: 621 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

+22 -20
View File
@@ -1,39 +1,41 @@
"""Render assets/icon.svg to assets/icon.ico (PNG-compressed entries at the usual Windows sizes).
"""Build the app icons from images/mtga-assistant-icon.png (the single source image).
Run with: uv run python packaging/make_icon.py
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, QPainter
from PySide6.QtSvg import QSvgRenderer
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 render_png(renderer: QSvgRenderer, size: int) -> bytes:
img = QImage(size, size, QImage.Format.Format_ARGB32)
img.fill(Qt.GlobalColor.transparent)
painter = QPainter(img)
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
renderer.render(painter)
painter.end()
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)
img.save(buf, "PNG")
return bytes(data)
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])
renderer = QSvgRenderer(str(ROOT / "assets/icon.svg"))
pngs = [(size, render_png(renderer, size)) for size in SIZES]
# ICONDIR header, then one ICONDIRENTRY per image, then the PNG data.
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("<HHH", 0, 1, len(pngs))
offset = 6 + 16 * len(pngs)
for size, png in pngs:
@@ -41,10 +43,10 @@ def main() -> None:
out += struct.pack("<BBBBHHII", dim, dim, 0, 0, 1, 32, len(png), offset)
offset += len(png)
out += b"".join(png for _, png in pngs)
(ROOT / "assets/icon.ico").write_bytes(out)
# The app loads this at runtime (window/taskbar icon), so it lives inside the package.
(ROOT / "src/mtga_assistant/icon.png").write_bytes(dict(pngs)[256])
print(f"wrote assets/icon.ico ({len(out)} bytes) and src/mtga_assistant/icon.png")
ico = SOURCE.with_suffix(".ico")
ico.write_bytes(out)
shutil.copyfile(SOURCE, ROOT / "src" / "mtga_assistant" / "icon.png")
print(f"wrote {ico.relative_to(ROOT)} and src/mtga_assistant/icon.png from {SOURCE.relative_to(ROOT)}")
if __name__ == "__main__":
+1 -2
View File
@@ -14,7 +14,6 @@ a = Analysis(
# Qt modules the app doesn't use; keeps the bundle smaller.
excludes=[
"tkinter",
"PySide6.QtNetwork",
"PySide6.QtQml",
"PySide6.QtQuick",
"PySide6.QtSql",
@@ -37,6 +36,6 @@ exe = EXE(
exclude_binaries=True,
name="MTGA Assistant",
console=False,
icon=str(ROOT / "assets" / "icon.ico") if sys.platform == "win32" else None,
icon=str(ROOT / "images" / "mtga-assistant-icon.ico") if sys.platform == "win32" else None,
)
coll = COLLECT(exe, a.binaries, a.datas, name="MTGA Assistant")
Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB