fix: Windows 图标支持多分辨率 RGBA 圆角,修复 ICO 只有 16x16 单帧的问题

This commit is contained in:
小鱼开发
2026-05-19 11:35:39 +08:00
parent c6fd452e87
commit 09ea37bae1
7 changed files with 37 additions and 18 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

+37 -18
View File
@@ -4,6 +4,8 @@
from PIL import Image, ImageDraw
import subprocess
import os
import struct
import io
# 配置
LOGO_PATH = "../../public/assets/logo.png"
@@ -33,7 +35,8 @@ def generate_icon(size):
# 加载并缩放 logo
logo = Image.open(LOGO_PATH).convert("RGBA")
logo_size = int(min(size) * LOGO_SCALE)
logo.thumbnail((logo_size, logo_size), Image.LANCZOS)
# 使用 resize 确保精确尺寸,避免 thumbnail 导致的尺寸偏差
logo = logo.resize((logo_size, logo_size), Image.LANCZOS)
# 居中绘制 logo
x = (size[0] - logo.width) // 2
@@ -43,6 +46,36 @@ def generate_icon(size):
return bg
def save_ico(images, sizes, filepath):
"""手动构建多帧 ICO 文件(PIL 原生 save 不支持 append_images for ICO"""
num_images = len(images)
# ICONDIR: Reserved(2) + Type(2) + Count(2)
header = struct.pack("<HHH", 0, 1, num_images)
offset = 6 + 16 * num_images
entries = []
data = b""
for img, size in zip(images, sizes):
buf = io.BytesIO()
img.save(buf, format="PNG")
png_bytes = buf.getvalue()
w = size if size < 256 else 0
h = size if size < 256 else 0
# ICONDIRENTRY: Width(1) + Height(1) + Colors(1) + Reserved(1) + Planes(2) + BPP(2) + Size(4) + Offset(4)
entry = struct.pack("<BBBBHHII", w, h, 0, 0, 1, 32, len(png_bytes), offset)
entries.append(entry)
data += png_bytes
offset += len(png_bytes)
with open(filepath, "wb") as f:
f.write(header)
for e in entries:
f.write(e)
f.write(data)
def main():
os.chdir(os.path.dirname(os.path.abspath(__file__)))
@@ -82,24 +115,10 @@ def main():
)
print("Generated icon.icns")
# 生成 ICOWindows 需要多分辨率)
# 生成 ICOWindows 需要多分辨率,保留 RGBA 透明通道实现圆角效果
ico_sizes = [16, 32, 48, 64, 128, 256]
ico_images = []
for s in ico_sizes:
img = generate_icon((s, s))
# ICO 需要 RGB 模式
if img.mode == "RGBA":
rgb = Image.new("RGB", img.size, (255, 255, 255))
rgb.paste(img, mask=img.split()[3])
ico_images.append(rgb)
else:
ico_images.append(img)
ico_images[0].save(
f"{OUTPUT_DIR}/icon.ico",
format="ICO",
sizes=[(s, s) for s in ico_sizes],
)
ico_images = [generate_icon((s, s)) for s in ico_sizes]
save_ico(ico_images, ico_sizes, f"{OUTPUT_DIR}/icon.ico")
print("Generated icon.ico")
# 清理临时目录
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 379 B

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 27 KiB