05a685c952
- calculator_designer_ext(Day2 增强版:表达式求值 + 括号,递归下降解析器)接入 cmake - calculator_mainwindow(Day3 上午):增强版计算器装进 QMainWindow, 菜单/状态栏/历史停靠窗,纯代码 + 显式 connect,与 mainwindow_showcase 形成坑卡对照 - calculator_mainwindow_qss(Day3 下午):上午版 + QSS 双主题美化(按键分色/伪状态/深浅切换) - 验证 mainwindow_showcase(QMainWindow 六大组件综合演示,.ui + .qrc) - OUTLINE_4DAY.md / ASSIGNMENTS.md Day3 衔接增强版起点 + 参考实现指引 - 补提交 Day2 calculator/ 与 calculator_designer/ 参考实现(CMakeLists 已引用) - 全量构建 28/28,4 目标离屏自测退出码 0 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
84 lines
2.8 KiB
Python
84 lines
2.8 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""生成 qt_mainwindow_showcase 所需的极简 PNG 图标。
|
||
|
||
仅用 Python 标准库(zlib + struct)手写最小 PNG 编码器,无第三方依赖。
|
||
幂等:重复运行覆盖生成相同文件。
|
||
|
||
python gen_icons.py # *nix / 已配置 py 启动器的 Windows
|
||
py gen_icons.py # Windows 官方 py 启动器
|
||
"""
|
||
import os
|
||
import struct
|
||
import zlib
|
||
|
||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||
ICONS_DIR = os.path.join(HERE, "icons")
|
||
|
||
# 5×7 点阵字模("1" = 前景白色像素)
|
||
GLYPHS = {
|
||
"M": ["10001", "11011", "10101", "10001", "10001", "10001", "10001"],
|
||
"N": ["10001", "11001", "10101", "10011", "10001", "10001", "10001"],
|
||
"Q": ["01110", "10001", "10001", "10001", "10101", "10011", "01111"],
|
||
"A": ["01110", "10001", "10001", "11111", "10001", "10001", "10001"],
|
||
"D": ["11110", "10001", "10001", "10001", "10001", "10001", "11110"],
|
||
}
|
||
|
||
|
||
def write_png(path, width, height, rgb_rows):
|
||
"""写一张 8 位、颜色类型 2(RGB)的 PNG。rgb_rows: 每行 width*3 个 0-255 整数。"""
|
||
def chunk(tag, data):
|
||
body = tag + data
|
||
return (struct.pack(">I", len(data)) + body +
|
||
struct.pack(">I", zlib.crc32(body) & 0xffffffff))
|
||
|
||
sig = b"\x89PNG\r\n\x1a\n"
|
||
ihdr = struct.pack(">IIBBBBB", width, height, 8, 2, 0, 0, 0)
|
||
raw = b"".join(b"\x00" + bytes(row) for row in rgb_rows) # 每行前加 filter byte(0)
|
||
idat = zlib.compress(raw, 9)
|
||
with open(path, "wb") as f:
|
||
f.write(sig + chunk(b"IHDR", ihdr) + chunk(b"IDAT", idat) + chunk(b"IEND", b""))
|
||
|
||
|
||
def make_icon(size, bg, letter):
|
||
"""生成 size×size 的像素矩阵:纯色背景 + 居中白色字母。"""
|
||
glyph = GLYPHS[letter]
|
||
bw, bh = 5, 7
|
||
pix = 1 if size <= 16 else 2 # 16px 用 1:1 字模,32px 放大 2 倍
|
||
gw, gh = bw * pix, bh * pix
|
||
ox = (size - gw) // 2
|
||
oy = (size - gh) // 2
|
||
rows = []
|
||
for y in range(size):
|
||
row = []
|
||
for x in range(size):
|
||
gx, gy = (x - ox) // pix, (y - oy) // pix
|
||
if 0 <= gx < bw and 0 <= gy < bh and glyph[gy][gx] == "1":
|
||
row.extend((255, 255, 255))
|
||
else:
|
||
row.extend(bg)
|
||
rows.append(row)
|
||
return rows
|
||
|
||
|
||
# (文件名, 尺寸, 背景色 RGB, 字母)
|
||
SPECS = [
|
||
("app.png", 32, (30, 80, 180), "M"),
|
||
("new.png", 16, (40, 150, 70), "N"),
|
||
("quit.png", 16, (200, 50, 50), "Q"),
|
||
("about.png", 16, (220, 140, 30), "A"),
|
||
("dock.png", 16, (130, 60, 180), "D"),
|
||
]
|
||
|
||
|
||
def main():
|
||
os.makedirs(ICONS_DIR, exist_ok=True)
|
||
for name, size, bg, letter in SPECS:
|
||
write_png(os.path.join(ICONS_DIR, name), size, size, make_icon(size, bg, letter))
|
||
print(f"wrote {name} ({size}x{size})")
|
||
print(f"done -> {ICONS_DIR}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|