diff --git a/.gitignore b/.gitignore index 47275e5..1eabbe7 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ __pycache__/ debug.log .vscode/ .idea/ +icon.png diff --git a/README.md b/README.md index 95e1ae1..e5daa81 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ESP32-S3 类产品的产线入库测试夹具。Python + tkinter 编写,打包为单文件 `.exe`,仓库人员双击即用,不需要装 Python。 -**版本**:v2.1.0 +**版本**:v2.1.1 --- @@ -207,7 +207,15 @@ seaborn bokeh cv2 tables numba llvmlite torch tensorflow sklearn ## 七、版本说明 -### v2.1.0(当前) +### v2.1.1(当前) + +- 新增自定义图标:蓝色渐变 + 白色 IC 芯片轮廓 + 绿色对勾,多尺寸(16/24/32/48/64/128/256)嵌入 exe,窗口标题栏也用同图标 +- 加 `APP_VERSION` 常量,更新一处即可全局同步 +- 产品栏右上角显示版本号(深灰加粗),方便仓库人员一眼看清当前版本 +- 窗口标题不再带版本号(重复) +- 新增 `generate_icon.py` 独立脚本,手工写多帧 ICO(绕开 PIL writer 只保留单帧的 bug) + +### v2.1.0 **核心改动**(相对 v2.0.0): - **SN 不再被 FAIL 占用**:FAIL 行 SN 列留空,PASS 才占编号 diff --git a/generate_icon.py b/generate_icon.py new file mode 100644 index 0000000..01f52d4 --- /dev/null +++ b/generate_icon.py @@ -0,0 +1,109 @@ +"""一次性脚本:生成多尺寸 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("