Files
BoltClam/scripts/generate_assets.py
TheMajesticMagicianandClaude Code addd00364d BoltClam 1.0.0: ClamAV desktop protection with Bolt sign-in
Adds the PyQt6 Windows client (Homepage, Scan & results, About & updates, Settings), ClamAV scanning and quarantine, browser-download watch with an exclusive scan gate, Bolt loopback/PKCE sign-in with DPAPI key storage, Gitea release feed with checksum verification, opt-in diagnostics, and Windows/portable build tooling.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-25 16:21:14 -06:00

114 lines
3.4 KiB
Python

"""Generate the small raster assets used by the Qt stylesheet and Windows icon.
Run with the project venv from the repository root:
QT_QPA_PLATFORM=offscreen .venv/bin/python scripts/generate_assets.py
"""
from __future__ import annotations
import struct
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "src"))
from PyQt6.QtCore import QBuffer, QByteArray, QIODevice, QPointF, QRectF, Qt # noqa: E402
from PyQt6.QtGui import QColor, QImage, QPainter, QPainterPath, QPen, QPixmap # noqa: E402
from PyQt6.QtWidgets import QApplication # noqa: E402
from boltclam.ui import brand # noqa: E402
RESOURCES = ROOT / "resources"
def _png_bytes(pixmap: QPixmap) -> bytes:
data = QByteArray()
buffer = QBuffer(data)
buffer.open(QIODevice.OpenModeFlag.WriteOnly)
pixmap.save(buffer, "PNG")
buffer.close()
return bytes(data)
def _check() -> None:
size = 18
pixmap = QPixmap(size, size)
pixmap.fill(Qt.GlobalColor.transparent)
painter = QPainter(pixmap)
painter.setRenderHint(QPainter.RenderHint.Antialiasing, True)
pen = QPen(QColor("#201704"), 2.4, Qt.PenStyle.SolidLine,
Qt.PenCapStyle.RoundCap, Qt.PenJoinStyle.RoundJoin)
painter.setPen(pen)
path = QPainterPath(QPointF(4.2, 9.3))
path.lineTo(7.4, 12.5)
path.lineTo(13.8, 5.4)
painter.drawPath(path)
painter.end()
pixmap.save(str(RESOURCES / "check.png"), "PNG")
def _radio() -> None:
size = 17
pixmap = QPixmap(size, size)
pixmap.fill(Qt.GlobalColor.transparent)
painter = QPainter(pixmap)
painter.setRenderHint(QPainter.RenderHint.Antialiasing, True)
painter.setPen(Qt.PenStyle.NoPen)
painter.setBrush(QColor("#201704"))
painter.drawEllipse(QRectF(5.0, 5.0, 7.0, 7.0))
painter.end()
pixmap.save(str(RESOURCES / "radio.png"), "PNG")
def _chevron() -> None:
size = 14
pixmap = QPixmap(size, size)
pixmap.fill(Qt.GlobalColor.transparent)
painter = QPainter(pixmap)
painter.setRenderHint(QPainter.RenderHint.Antialiasing, True)
painter.setPen(QPen(QColor("#8BA7B2"), 1.7, Qt.PenStyle.SolidLine,
Qt.PenCapStyle.RoundCap, Qt.PenJoinStyle.RoundJoin))
path = QPainterPath(QPointF(3.2, 5.2))
path.lineTo(7.0, 9.0)
path.lineTo(10.8, 5.2)
painter.drawPath(path)
painter.end()
pixmap.save(str(RESOURCES / "chevron_down.png"), "PNG")
def _ico() -> None:
sizes = (16, 24, 32, 48, 64, 128, 256)
images: list[tuple[int, bytes]] = []
for size in sizes:
pixmap = brand.pixmap(size)
images.append((size, _png_bytes(pixmap)))
header = struct.pack("<HHH", 0, 1, len(images))
offset = 6 + 16 * len(images)
entries = b""
payload = b""
for size, data in images:
width = 0 if size >= 256 else size
height = 0 if size >= 256 else size
entries += struct.pack("<BBBBHHII", width, height, 0, 0, 1, 32,
len(data), offset)
offset += len(data)
payload += data
(RESOURCES / "boltclam.ico").write_bytes(header + entries + payload)
brand.pixmap(256).save(str(RESOURCES / "boltclam.png"), "PNG")
def main() -> int:
app = QApplication.instance() or QApplication(sys.argv)
RESOURCES.mkdir(parents=True, exist_ok=True)
_check()
_radio()
_chevron()
_ico()
print("assets written to", RESOURCES)
return 0
if __name__ == "__main__":
raise SystemExit(main())