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:
1 parent
c4533d12c0
commit
fb6220155c
7 files changed
+23
-33
No files matched your search
Binary file not shown.
|
Before Width: | Height: | Size: 27 KiB |
@@ -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
@@ -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__":
|
||||
|
||||
@@ -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 |
Reference in new issue
Block a user