-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmake_icns.py
More file actions
120 lines (94 loc) · 3.85 KB
/
make_icns.py
File metadata and controls
120 lines (94 loc) · 3.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# -*- coding: utf-8 -*-
"""
make-icns.py
在 macOS 下把任意图片做成 .icns 图标并自动用系统预览打开。
用法:
./make-icns.py input.png # 透明背景,默认用 Pillow
./make-icns.py input.jpg "#FF00FF" # 指定背景色
./make-icns.py input.tiff -o MyIcon.icns # 指定输出文件名
./make-icns.py input.png --engine iconutil # 强制使用 iconutil
"""
import os
import sys
import argparse
import tempfile
import subprocess
from PIL import Image
from icon_common import parse_hex_color, square_image
if sys.platform != "darwin": # 非 macOS 立即退出
sys.exit("ERROR: 该脚本只能运行在 macOS 上。")
# icns 所需全部分辨率
ICNS_SIZES = [16, 32, 64, 128, 256, 512, 1024]
def build_icns_pillow(source_img: Image.Image, output_icns: str):
"""使用 Pillow 生成 .icns(跨平台,无需 iconutil)"""
# 准备所有分辨率版本
icons = []
for size in ICNS_SIZES:
for scale, suffix in [(1, ""), (2, "@2x")]:
px = size * scale
img_scaled = source_img.resize((px, px), Image.LANCZOS)
# Pillow 5.1+ 会根据图像尺寸自动匹配到对应槽位
icons.append(img_scaled)
# 第一张作为主图,其余作为 append_images
icons[0].save(output_icns, format="ICNS", append_images=icons[1:])
print(f"✅ 已生成 -> {output_icns}(Pillow 引擎,含尺寸:{ICNS_SIZES})")
def build_icns_iconutil(source_img: Image.Image, output_icns: str):
"""生成 .icns 文件(iconutil 版)"""
tempdir = tempfile.mkdtemp()
iconset = os.path.join(tempdir, "Icon.iconset")
os.makedirs(iconset)
for size in ICNS_SIZES:
# 1× 和 2× Retina 版本
for scale, suffix in [(1, ""), (2, "@2x")]:
px = size * scale
img_scaled = source_img.resize((px, px), Image.LANCZOS)
filename = f"icon_{size}x{size}{suffix}.png"
img_scaled.save(os.path.join(iconset, filename))
# 调用系统 iconutil 生成 icns
subprocess.run(["iconutil", "-c", "icns", iconset, "-o", output_icns], check=True)
# 清理
subprocess.run(["rm", "-rf", tempdir])
print(f"✅ 已生成 -> {output_icns}(iconutil 引擎,含尺寸:{ICNS_SIZES})")
def build_icns(source_img: Image.Image, output_icns: str, engine: str = "pillow"):
if engine == "pillow":
build_icns_pillow(source_img, output_icns)
else:
build_icns_iconutil(source_img, output_icns)
def open_in_viewer(path: str):
"""用 macOS 默认的 icns 查看器(Preview)打开"""
subprocess.run(["open", path])
def main():
parser = argparse.ArgumentParser(description="把任意图片做成 macOS .icns 图标")
parser.add_argument("input", help="输入图片路径")
parser.add_argument("bgcolor", nargs="?", help="背景色(十六进制,可选,默认透明)")
parser.add_argument("-o", "--output", help="输出 .icns 文件名(可选)")
parser.add_argument(
"--engine",
choices=["pillow", "iconutil"],
default="pillow",
help="选择生成引擎:pillow(默认)或 iconutil",
)
args = parser.parse_args()
if not os.path.isfile(args.input):
sys.exit("输入文件不存在")
# 1. 读图
img = Image.open(args.input).convert("RGBA")
# 2. 背景色
if args.bgcolor:
bg_color = parse_hex_color(args.bgcolor)
else:
bg_color = None # 透明
# 3. 正方形化
square = square_image(img, bg_color)
# 4. 输出文件名
if args.output:
out_icns = args.output
else:
base, _ = os.path.splitext(args.input)
out_icns = base + ".icns"
# 5. 生成 icns
build_icns(square, out_icns, engine=args.engine)
# 6. 打开查看
open_in_viewer(out_icns)
if __name__ == "__main__":
main()