-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgenerate-icon.py
More file actions
executable file
·210 lines (175 loc) · 5.12 KB
/
generate-icon.py
File metadata and controls
executable file
·210 lines (175 loc) · 5.12 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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#!/usr/bin/env python3
"""
Generate PulseRT app icon with pink background and "RT" initials.
Usage: python3 generate-icon.py
If Pillow is not installed, the script will create a virtual environment
and install it automatically.
"""
import os
import subprocess
import sys
def ensure_pillow():
"""Ensure Pillow is available, installing in venv if needed."""
try:
from PIL import Image, ImageDraw, ImageFont
return Image, ImageDraw, ImageFont
except ImportError:
pass
# Check if we're already in our venv
venv_path = os.path.join(os.path.dirname(__file__), ".venv")
venv_python = os.path.join(venv_path, "bin", "python3")
if sys.executable == venv_python:
# We're in the venv but Pillow still not available
print("Installing Pillow...")
subprocess.check_call([sys.executable, "-m", "pip", "install", "Pillow", "-q"])
from PIL import Image, ImageDraw, ImageFont
return Image, ImageDraw, ImageFont
# Create venv if it doesn't exist
if not os.path.exists(venv_path):
print("Creating virtual environment...")
subprocess.check_call([sys.executable, "-m", "venv", venv_path])
# Re-run this script in the venv
print("Running in virtual environment...")
os.execv(venv_python, [venv_python, __file__] + sys.argv[1:])
Image, ImageDraw, ImageFont = ensure_pillow()
# Icon sizes for macOS app icon
SIZES = [16, 32, 64, 128, 256, 512, 1024]
# Colors
BG_COLOR = "#FF6B9D"
FG_COLOR = "#FFFFFF"
OUTPUT_DIR = "PulseRT/Resources/Assets.xcassets/AppIcon.appiconset"
def create_icon(size: int) -> Image.Image:
"""Create a single icon at the specified size."""
img = Image.new("RGBA", (size, size), BG_COLOR)
draw = ImageDraw.Draw(img)
# Calculate font size (roughly 45% of icon size for good proportions)
font_size = int(size * 0.45)
# Try to use SF Pro or fall back to system fonts
font = None
font_paths = [
"/System/Library/Fonts/SFNSText.ttf",
"/System/Library/Fonts/SFNS.ttf",
"/Library/Fonts/SF-Pro-Text-Bold.otf",
"/System/Library/Fonts/Helvetica.ttc",
"/System/Library/Fonts/HelveticaNeue.ttc",
]
for font_path in font_paths:
if os.path.exists(font_path):
try:
font = ImageFont.truetype(font_path, font_size)
break
except (IOError, OSError):
continue
if font is None:
# Fall back to default font
font = ImageFont.load_default()
text = "RT"
# Get text bounding box for centering
bbox = draw.textbbox((0, 0), text, font=font)
text_width = bbox[2] - bbox[0]
text_height = bbox[3] - bbox[1]
# Center the text
x = (size - text_width) // 2
y = (size - text_height) // 2 - bbox[1] # Adjust for font baseline
# Draw the text
draw.text((x, y), text, fill=FG_COLOR, font=font)
return img
def main():
# Create output directory
os.makedirs(OUTPUT_DIR, exist_ok=True)
print(f"Generating icons in {OUTPUT_DIR}...")
# Generate icons at each size
for size in SIZES:
img = create_icon(size)
filename = f"icon_{size}x{size}.png"
filepath = os.path.join(OUTPUT_DIR, filename)
img.save(filepath, "PNG")
print(f" Created {filename}")
# Create Contents.json for Xcode asset catalog
contents = """{
"images" : [
{
"filename" : "icon_16x16.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "16x16"
},
{
"filename" : "icon_32x32.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "16x16"
},
{
"filename" : "icon_32x32.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "32x32"
},
{
"filename" : "icon_64x64.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "32x32"
},
{
"filename" : "icon_128x128.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "128x128"
},
{
"filename" : "icon_256x256.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "128x128"
},
{
"filename" : "icon_256x256.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "256x256"
},
{
"filename" : "icon_512x512.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "256x256"
},
{
"filename" : "icon_512x512.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "512x512"
},
{
"filename" : "icon_1024x1024.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "512x512"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
"""
contents_path = os.path.join(OUTPUT_DIR, "Contents.json")
with open(contents_path, "w") as f:
f.write(contents)
print(f" Created Contents.json")
# Create Assets.xcassets Contents.json
assets_contents = """{
"info" : {
"author" : "xcode",
"version" : 1
}
}
"""
assets_dir = "PulseRT/Resources/Assets.xcassets"
with open(os.path.join(assets_dir, "Contents.json"), "w") as f:
f.write(assets_contents)
print("\nIcon generation complete!")
if __name__ == "__main__":
main()