fix: Windows icons use square fill, macOS keeps rounded

- Windows .ico and SquareLogo: content fills 100% canvas, no transparency
- macOS .icns and PNG: keep 80.5% rounded rectangle
- Fixes white/grey square background and blur on Windows
This commit is contained in:
小鱼开发
2026-05-20 10:07:10 +08:00
parent 2d7e1473a9
commit 0abc032682
12 changed files with 31 additions and 10 deletions
+31 -10
View File
@@ -43,13 +43,12 @@ def create_rounded_rect_mask(size: int, radius: int) -> Image.Image:
return mask
def compose_icon(size: int, source: Image.Image) -> Image.Image:
"""原图作为整体,缩放至画布 CONTENT_RATIO,居中,裁成圆角矩形"""
def compose_icon(size: int, source: Image.Image, rounded: bool = True) -> Image.Image:
"""原图作为整体,缩放至画布 CONTENT_RATIO,居中"""
canvas = Image.new("RGBA", (size, size), (0, 0, 0, 0))
plate_size = int(size * CONTENT_RATIO)
plate_offset = (size - plate_size) // 2
radius = int(plate_size * CORNER_RATIO)
# 原图等比缩放,短边充满 plate_size
src_w, src_h = source.size
@@ -63,12 +62,32 @@ def compose_icon(size: int, source: Image.Image) -> Image.Image:
top = (new_h - plate_size) // 2
img = resized.crop((left, top, left + plate_size, top + plate_size))
# 圆角蒙版裁剪
mask = create_rounded_rect_mask(plate_size, radius)
canvas.paste(img, (plate_offset, plate_offset), mask)
if rounded:
# 圆角蒙版裁剪(macOS / Linux
radius = int(plate_size * CORNER_RATIO)
mask = create_rounded_rect_mask(plate_size, radius)
canvas.paste(img, (plate_offset, plate_offset), mask)
else:
# 正方形填满(Windows 专用)
canvas.paste(img, (plate_offset, plate_offset))
return canvas
def compose_icon_windows(size: int, source: Image.Image) -> Image.Image:
"""Windows 专用:原图填满整个画布 100%,无圆角,无透明边距"""
# 原图等比缩放,短边充满画布
src_w, src_h = source.size
ratio = max(size / src_w, size / src_h)
new_w = int(src_w * ratio)
new_h = int(src_h * ratio)
resized = source.resize((new_w, new_h), Image.LANCZOS)
# 居中裁剪到画布尺寸
left = (new_w - size) // 2
top = (new_h - size) // 2
return resized.crop((left, top, left + size, top + size))
def generate_icns(source: Image.Image, output_path: str):
"""生成 macOS .icns 文件"""
import tempfile
@@ -79,10 +98,10 @@ def generate_icns(source: Image.Image, output_path: str):
iconset_dir = tempfile.mkdtemp(suffix=".iconset")
for sz in sizes:
img = compose_icon(sz, source)
img = compose_icon(sz, source, rounded=True)
img.save(os.path.join(iconset_dir, f"icon_{sz}x{sz}.png"))
if sz <= 512:
img2x = compose_icon(sz * 2, source)
img2x = compose_icon(sz * 2, source, rounded=True)
img2x.save(os.path.join(iconset_dir, f"icon_{sz}x{sz}@2x.png"))
subprocess.run(
@@ -102,7 +121,8 @@ def generate_ico(source: Image.Image, output_path: str):
entries = []
for sz in sizes:
img = compose_icon(sz, source)
# Windows .ico 填满画布,无圆角,无透明边距
img = compose_icon_windows(sz, source)
buf = io.BytesIO()
img.save(buf, format="PNG")
data = buf.getvalue()
@@ -137,9 +157,10 @@ def main():
compose_icon(size, source).save(path)
print(f"已生成: {filename} ({size}x{size})")
# Windows Square Logo 填满画布,无圆角,无透明边距
for filename, size in SQUARE_SIZES:
path = os.path.join(ICONS_DIR, filename)
compose_icon(size, source).save(path)
compose_icon_windows(size, source).save(path)
print(f"已生成: {filename} ({size}x{size})")
generate_icns(source, os.path.join(ICONS_DIR, "icon.icns"))
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 5.6 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: 997 B

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 23 KiB