#!/usr/bin/env python3 """ 闲言APP — 系统托盘图标生成脚本 创建时间: 2026-06-18 更新时间: 2026-06-22 作用: 用 Pillow 生成 macOS/Windows 托盘图标 PNG + ICO(浅色+深色两套) 设计: 对话气泡 + 三条横线,体现"记录言语"主题 输出: - assets/images/tray_icon_light.png (黑色图标,用于 macOS template + Win 浅色主题) - assets/images/tray_icon_dark.png (白色图标,用于 Win 深色主题) - assets/images/tray_icon_light_32.png (32x32 高清版) - assets/images/tray_icon_dark_32.png (32x32 高清版) - windows/runner/resources/tray_icon_light.ico (黑色图标,Win 浅色主题) - windows/runner/resources/tray_icon_dark.ico (白色图标,Win 深色/纯黑主题) """ import os from PIL import Image, ImageDraw # ============================================================ # 配置 # ============================================================ PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) OUTPUT_DIR = os.path.join(PROJECT_ROOT, 'assets', 'images') WIN_ICO_DIR = os.path.join(PROJECT_ROOT, 'windows', 'runner', 'resources') SIZES = [16, 32] # 生成 16x16 和 32x32 两种尺寸 ICO_SIZES = [16, 24, 32, 48, 64] # ICO 文件包含多种尺寸 # 颜色定义 COLOR_LIGHT = (0, 0, 0, 255) # 黑色(浅色主题用) COLOR_DARK = (255, 255, 255, 255) # 白色(深色主题用) COLOR_TRANSPARENT = (0, 0, 0, 0) def draw_tray_icon(size: int, color: tuple) -> Image.Image: """绘制托盘图标 设计: - 对话气泡(圆角矩形)+ 三条横线 + 气泡尾巴 - 单色设计,简洁现代 """ # 创建透明背景 img = Image.new('RGBA', (size, size), COLOR_TRANSPARENT) draw = ImageDraw.Draw(img) # 缩放因子(基于 16x16 设计) scale = size / 16.0 def s(v): """缩放坐标""" return int(v * scale) # ============================================================ # 1. 对话气泡主体(圆角矩形) # ============================================================ # 气泡位置:左上 (1, 1) 到右下 (15, 11) bubble_x1, bubble_y1 = s(1), s(1) bubble_x2, bubble_y2 = s(15), s(11) bubble_radius = s(2) # 绘制圆角矩形气泡 draw.rounded_rectangle( [bubble_x1, bubble_y1, bubble_x2, bubble_y2], radius=bubble_radius, fill=color, ) # ============================================================ # 2. 气泡尾巴(左下角,指向说话者) # ============================================================ tail_points = [ (s(3), s(11)), # 尾巴起点(气泡底部) (s(3), s(14)), # 尾巴尖 (s(6), s(11)), # 尾巴终点(气泡底部) ] draw.polygon(tail_points, fill=color) # ============================================================ # 3. 气泡内三条横线(代表文字) # ============================================================ line_color = COLOR_TRANSPARENT # 用透明色"挖出"横线 line_thickness = max(1, s(1)) # 三条横线的位置(在气泡内部居中) line_x1 = s(3) line_x2_short = s(10) # 短线结束 line_x2_long = s(13) # 长线结束 # 第一条横线(短) draw.rectangle( [line_x1, s(4), line_x2_short, s(4) + line_thickness - 1], fill=line_color, ) # 第二条横线(长) draw.rectangle( [line_x1, s(6), line_x2_long, s(6) + line_thickness - 1], fill=line_color, ) # 第三条横线(中) draw.rectangle( [line_x1, s(8), s(11), s(8) + line_thickness - 1], fill=line_color, ) return img def main(): """主函数:生成所有图标""" os.makedirs(OUTPUT_DIR, exist_ok=True) os.makedirs(WIN_ICO_DIR, exist_ok=True) for size in SIZES: # 浅色版(黑色图标) light_img = draw_tray_icon(size, COLOR_LIGHT) light_name = f'tray_icon_light{"" if size == 16 else f"_{size}"}.png' light_path = os.path.join(OUTPUT_DIR, light_name) light_img.save(light_path, 'PNG') print(f'✅ 生成: {light_path} ({size}x{size})') # 深色版(白色图标) dark_img = draw_tray_icon(size, COLOR_DARK) dark_name = f'tray_icon_dark{"" if size == 16 else f"_{size}"}.png' dark_path = os.path.join(OUTPUT_DIR, dark_name) dark_img.save(dark_path, 'PNG') print(f'✅ 生成: {dark_path} ({size}x{size})') # ============================================================ # 生成 Windows ICO 文件(包含多尺寸) # ============================================================ # 浅色 ICO(黑色图标,白天模式用) light_ico_images = [draw_tray_icon(s, COLOR_LIGHT) for s in ICO_SIZES] light_ico_path = os.path.join(WIN_ICO_DIR, 'tray_icon_light.ico') light_ico_images[0].save( light_ico_path, format='ICO', sizes=[(s, s) for s in ICO_SIZES], append_images=light_ico_images[1:], ) print(f'✅ 生成: {light_ico_path} (ICO 多尺寸)') # 深色 ICO(白色图标,深色/纯黑模式用) dark_ico_images = [draw_tray_icon(s, COLOR_DARK) for s in ICO_SIZES] dark_ico_path = os.path.join(WIN_ICO_DIR, 'tray_icon_dark.ico') dark_ico_images[0].save( dark_ico_path, format='ICO', sizes=[(s, s) for s in ICO_SIZES], append_images=dark_ico_images[1:], ) print(f'✅ 生成: {dark_ico_path} (ICO 多尺寸)') print('\n🎉 所有托盘图标生成完成!') if __name__ == '__main__': main()