47c6589e1d
- scripts/gen_icon.py: generates 256x256 SSH client icon (dark terminal window with >_ prompt and SSH connection nodes), outputs multi-size ICO (16-256px) + PNG - resources/icon.ico + icon.png: generated icon files - main.py: _get_icon_path() searches _MEIPASS (onefile), exe dir, source dir; sets app + window icon - build.spec: bundles icon files via datas=, sets exe icon=icon.ico - Windows taskbar will now show the custom icon instead of default PyInstaller icon
131 lines
4.2 KiB
Python
131 lines
4.2 KiB
Python
"""
|
||
生成 SSHClient 应用图标
|
||
- 深色圆角方块背景
|
||
- 终端窗口 + >_ 提示符 + SSH 连接线
|
||
输出: resources/icon.ico (多尺寸) + resources/icon.png (256x256)
|
||
"""
|
||
import os
|
||
from PIL import Image, ImageDraw, ImageFont
|
||
|
||
OUT_DIR = os.path.join(os.path.dirname(__file__), "resources")
|
||
os.makedirs(OUT_DIR, exist_ok=True)
|
||
|
||
SIZE = 256
|
||
|
||
def draw_icon(size: int) -> Image.Image:
|
||
"""绘制指定尺寸的图标"""
|
||
img = Image.new("RGBA", (size, size), (0, 0, 0, 0))
|
||
d = ImageDraw.Draw(img)
|
||
|
||
pad = int(size * 0.06)
|
||
rect = [pad, pad, size - pad, size - pad]
|
||
radius = int(size * 0.18)
|
||
|
||
# 背景渐变(模拟,用两层半透明)
|
||
d.rounded_rectangle(rect, radius=radius, fill=(30, 30, 46, 255))
|
||
|
||
# 上半部分亮色渐变
|
||
inner = [pad + 4, pad + 4, size - pad - 4, size // 2]
|
||
d.rounded_rectangle(inner, radius=radius - 2, fill=(40, 40, 60, 255))
|
||
|
||
# 终端窗口
|
||
tw_margin = int(size * 0.16)
|
||
tw_top = int(size * 0.20)
|
||
tw_bottom = int(size * 0.78)
|
||
tw_left = tw_margin
|
||
tw_right = size - tw_margin
|
||
tw_radius = int(size * 0.04)
|
||
|
||
# 终端窗口阴影
|
||
shadow_offset = max(2, size // 64)
|
||
d.rounded_rectangle(
|
||
[tw_left + shadow_offset, tw_top + shadow_offset,
|
||
tw_right + shadow_offset, tw_bottom + shadow_offset],
|
||
radius=tw_radius, fill=(0, 0, 0, 60)
|
||
)
|
||
|
||
# 终端窗口背景
|
||
d.rounded_rectangle(
|
||
[tw_left, tw_top, tw_right, tw_bottom],
|
||
radius=tw_radius, fill=(12, 12, 20, 255)
|
||
)
|
||
|
||
# 终端标题栏
|
||
tb_height = int(size * 0.055)
|
||
d.rounded_rectangle(
|
||
[tw_left, tw_top, tw_right, tw_top + tb_height],
|
||
radius=tw_radius, fill=(50, 50, 70, 255)
|
||
)
|
||
# 底部直角覆盖(标题栏只有上面圆角)
|
||
d.rectangle(
|
||
[tw_left, tw_top + tb_height - tw_radius, tw_right, tw_top + tb_height],
|
||
fill=(50, 50, 70, 255)
|
||
)
|
||
|
||
# 三个小圆点(macOS 风格窗口按钮)
|
||
dot_r = max(2, int(size * 0.016))
|
||
dot_y = tw_top + tb_height // 2
|
||
dot_start = tw_left + int(size * 0.04)
|
||
dot_gap = int(size * 0.045)
|
||
for i, color in enumerate([(239, 83, 80), (255, 167, 38), (102, 187, 106)]):
|
||
cx = dot_start + i * dot_gap
|
||
d.ellipse([cx - dot_r, dot_y - dot_r, cx + dot_r, dot_y + dot_r], fill=color)
|
||
|
||
# >_ 提示符
|
||
cx = tw_left + int(size * 0.06)
|
||
cy = tw_top + tb_height + int(size * 0.10)
|
||
line_w = max(2, int(size * 0.022))
|
||
arrow_len = int(size * 0.08)
|
||
gap = int(size * 0.02)
|
||
|
||
# > 符号
|
||
d.line([cx, cy, cx + arrow_len, cy + arrow_len // 2],
|
||
fill=(102, 187, 106), width=line_w)
|
||
d.line([cx, cy + arrow_len, cx + arrow_len, cy + arrow_len // 2],
|
||
fill=(102, 187, 106), width=line_w)
|
||
|
||
# _ 光标
|
||
cursor_x = cx + arrow_len + gap
|
||
cursor_w = int(size * 0.06)
|
||
cursor_h = max(2, int(size * 0.018))
|
||
d.rounded_rectangle(
|
||
[cursor_x, cy + arrow_len // 2 - cursor_h // 2,
|
||
cursor_x + cursor_w, cy + arrow_len // 2 + cursor_h // 2],
|
||
radius=max(1, cursor_h // 3), fill=(137, 180, 250)
|
||
)
|
||
|
||
# SSH 连接线(底部装饰)
|
||
line_y = tw_bottom + int(size * 0.05)
|
||
if line_y < size - pad:
|
||
# 连接节点
|
||
node_r = max(2, int(size * 0.012))
|
||
n1 = (tw_left + int(size * 0.04), line_y)
|
||
n2 = (tw_right - int(size * 0.04), line_y)
|
||
d.ellipse([n1[0]-node_r, n1[1]-node_r, n1[0]+node_r, n1[1]+node_r],
|
||
fill=(137, 180, 250))
|
||
d.ellipse([n2[0]-node_r, n2[1]-node_r, n2[0]+node_r, n2[1]+node_r],
|
||
fill=(137, 180, 250))
|
||
d.line([n1[0]+node_r, n1[1], n2[0]-node_r, n2[1]],
|
||
fill=(137, 180, 250, 160), width=max(1, line_w // 2))
|
||
|
||
return img
|
||
|
||
|
||
def main():
|
||
# 生成 256x256 主图
|
||
icon = draw_icon(SIZE)
|
||
png_path = os.path.join(OUT_DIR, "icon.png")
|
||
icon.save(png_path)
|
||
print(f"Saved {png_path} ({SIZE}x{SIZE})")
|
||
|
||
# 生成多尺寸 ICO(Pillow 自动从 256x256 缩放到各尺寸)
|
||
sizes = [(16, 16), (24, 24), (32, 32), (48, 48), (64, 64), (128, 128), (256, 256)]
|
||
ico_path = os.path.join(OUT_DIR, "icon.ico")
|
||
icon.save(ico_path, format="ICO", sizes=sizes)
|
||
print(f"Saved {ico_path} (sizes: {[s[0] for s in sizes]})")
|
||
print("Done!")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|