hardware-test/generate_icon.py

110 lines
3.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""一次性脚本:生成多尺寸 icon.ico芯片轮廓 + 绿色对勾,蓝色 Material 风格)。
生成正确的多帧 ICO 文件(手工写 ICONDIR + PNG 帧),避免 PIL 的 ICO writer 只保留单帧的 bug。
"""
import struct
from io import BytesIO
from pathlib import Path
from PIL import Image, ImageDraw
def make_base(size: int) -> Image.Image:
"""画一张 size×size 的图标 base image。"""
img = Image.new("RGBA", (size, size), (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
# 圆角方形背景 + 垂直蓝色渐变
for y in range(size):
t = y / size
r = int(25 + (66 - 25) * t)
g = int(118 + (165 - 118) * t)
b = int(210 + (245 - 210) * t)
draw.rectangle((0, y, size, y + 1), fill=(r, g, b, 255))
# 圆角裁切
mask = Image.new("L", (size, size), 0)
ImageDraw.Draw(mask).rounded_rectangle(
(0, 0, size - 1, size - 1), radius=int(size * 0.19), fill=255)
img.putalpha(mask)
# IC 芯片轮廓
s = size
chip_box = (int(s * 0.265), int(s * 0.352), int(s * 0.735), int(s * 0.648))
line_w = max(2, int(s * 0.024))
draw.rectangle(chip_box, outline=(255, 255, 255), width=line_w)
pin_w = max(2, int(s * 0.024))
pin_l = max(2, int(s * 0.047))
cx_left, cy_top, cx_right, cy_bot = chip_box
chip_w = cx_right - cx_left
chip_h = cy_bot - cy_top
# 上下引脚5 根)
for i in range(5):
x = cx_left + int(chip_w * (0.117 + 0.192 * i))
draw.rectangle((x - pin_w // 2, cy_top - pin_l, x + pin_w // 2, cy_top),
fill=(255, 255, 255))
draw.rectangle((x - pin_w // 2, cy_bot, x + pin_w // 2, cy_bot + pin_l),
fill=(255, 255, 255))
# 左右引脚3 根)
for i in range(3):
y = cy_top + int(chip_h * (0.185 + 0.302 * i))
draw.rectangle((cx_left - pin_l, y - pin_w // 2, cx_left, y + pin_w // 2),
fill=(255, 255, 255))
draw.rectangle((cx_right, y - pin_w // 2, cx_right + pin_l, y + pin_w // 2),
fill=(255, 255, 255))
# 中心:绿色对勾
check_pts = [
(int(s * 0.359), int(s * 0.492)),
(int(s * 0.453), int(s * 0.578)),
(int(s * 0.648), int(s * 0.383)),
]
check_w_max = max(3, int(s * 0.055))
for w in range(check_w_max, max(2, check_w_max - 6), -2):
draw.line(check_pts, fill=(76, 175, 80, 255), width=w, joint="curve")
# 白色细描边
draw.line(check_pts, fill=(255, 255, 255, 220), width=max(1, int(s * 0.008)), joint="curve")
return img
def write_ico(path: Path, sizes):
"""手工构造一个多帧 ICO 文件(每帧用 PNG 编码Windows Vista+ 通用)。"""
images_png = []
for sz in sizes:
img = make_base(sz)
buf = BytesIO()
img.save(buf, format="PNG")
images_png.append((sz, buf.getvalue()))
with open(path, "wb") as f:
# ICONDIR
f.write(struct.pack("<HHH", 0, 1, len(images_png)))
# ICONDIRENTRY × n
offset = 6 + 16 * len(images_png)
for sz, data in images_png:
w = sz if sz < 256 else 0 # 256 用 0 表示
f.write(struct.pack("<BBBBHHII",
w, w, 0, 0,
1, 32,
len(data), offset))
offset += len(data)
# 图像数据
for _, data in images_png:
f.write(data)
if __name__ == "__main__":
sizes = [16, 24, 32, 48, 64, 128, 256]
out = Path(__file__).parent / "icon.ico"
write_ico(out, sizes)
print(f"saved: {out} {out.stat().st_size} bytes (frames: {len(sizes)})")
# 顺便存一张大图 png 方便预览
make_base(512).save(Path(__file__).parent / "icon.png", format="PNG")