Files
Ubuntu 32b43f85bd a
2026-07-03 16:58:28 +08:00

404 lines
13 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
创建Material Design风格的图标
使用简单的几何图形模拟Material图标
"""
from PIL import Image, ImageDraw, ImageFont
import os
# Material Design 颜色
COLORS = {
'primary': '#6200EE',
'primary_variant': '#3700B3',
'secondary': '#03DAC6',
'background': '#FFFFFF',
'surface': '#FFFFFF',
'error': '#B00020',
'on_primary': '#FFFFFF',
'on_secondary': '#000000',
'on_background': '#000000',
'on_surface': '#000000',
'on_error': '#FFFFFF'
}
# 图标配置
ICONS = {
'home': {
'outline': 'M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z',
'filled': 'M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z'
},
'apps': {
'outline': 'M4 8h4V4H4v4zm6 12h4v-4h-4v4zm-6 0h4v-4H4v4zm0-6h4v-4H4v4zm6 0h4v-4h-4v4zm6-10v4h4V4h-4zm-6 4h4V4h-4v4zm6 6h4v-4h-4v4zm0 6h4v-4h-4v4z',
'filled': 'M4 8h4V4H4v4zm6 12h4v-4h-4v4zm-6 0h4v-4H4v4zm0-6h4v-4H4v4zm6 0h4v-4h-4v4zm6-10v4h4V4h-4zm-6 4h4V4h-4v4zm6 6h4v-4h-4v4zm0 6h4v-4h-4v4z'
},
'chat': {
'outline': 'M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z',
'filled': 'M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2z'
},
'layers': {
'outline': 'M11.99 18.54l-7.37-5.73L3 14.07l9 7 9-7-1.63-1.27-7.38 5.74zM12 16l7.36-5.73L21 9l-9-7-9 7 1.63 1.27L12 16z',
'filled': 'M11.99 18.54l-7.37-5.73L3 14.07l9 7 9-7-1.63-1.27-7.38 5.74zM12 16l7.36-5.73L21 9l-9-7-9 7 1.63 1.27L12 16z'
},
'person': {
'outline': 'M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z',
'filled': 'M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z'
}
}
def create_material_icon(name, style='outline', size=48):
"""创建Material Design图标"""
# 创建图像
img = Image.new('RGBA', (size, size), (255, 255, 255, 0))
draw = ImageDraw.Draw(img)
# 设置颜色
if style == 'outline':
color = COLORS['on_surface'] # 灰色
fill_color = None
else: # filled
color = COLORS['primary'] # 紫色
fill_color = COLORS['primary']
# 简化:使用几何图形代替SVG路径
center = size // 2
if name == 'home':
# 房子图标
if style == 'outline':
# 轮廓
draw.rectangle([center-10, center-6, center+10, center+6], outline=color, width=2)
draw.polygon([
(center-12, center-6),
(center, center-14),
(center+12, center-6)
], outline=color, width=2)
else:
# 填充
draw.rectangle([center-10, center-6, center+10, center+6], fill=fill_color)
draw.polygon([
(center-12, center-6),
(center, center-14),
(center+12, center-6)
], fill=fill_color)
elif name == 'apps':
# 九宫格图标
cell_size = size // 4
for i in range(3):
for j in range(3):
x1 = cell_size + i * cell_size - 4
y1 = cell_size + j * cell_size - 4
x2 = x1 + cell_size - 4
y2 = y1 + cell_size - 4
if style == 'outline':
draw.rectangle([x1, y1, x2, y2], outline=color, width=2)
else:
draw.rectangle([x1, y1, x2, y2], fill=fill_color)
elif name == 'chat':
# 聊天图标
if style == 'outline':
draw.rounded_rectangle([8, 8, size-8, size-8], radius=8, outline=color, width=2)
# 对话气泡尾巴
draw.polygon([
(size-20, size-8),
(size-12, size-8),
(size-16, size-2)
], outline=color, width=2)
else:
draw.rounded_rectangle([8, 8, size-8, size-8], radius=8, fill=fill_color)
# 对话气泡尾巴
draw.polygon([
(size-20, size-8),
(size-12, size-8),
(size-16, size-2)
], fill=fill_color)
elif name == 'layers':
# 层叠图标
if style == 'outline':
for i in range(3):
offset = i * 4
draw.rounded_rectangle(
[8+offset, 8+offset, size-8-offset, size-8-offset],
radius=6, outline=color, width=2
)
else:
for i in range(3):
offset = i * 4
alpha = 255 - i * 60
layer_color = fill_color + hex(alpha)[2:].zfill(2)
draw.rounded_rectangle(
[8+offset, 8+offset, size-8-offset, size-8-offset],
radius=6, fill=layer_color
)
elif name == 'person':
# 人物图标
if style == 'outline':
# 头部
draw.ellipse([center-8, center-12, center+8, center+4], outline=color, width=2)
# 身体
draw.rectangle([center-6, center+4, center+6, center+12], outline=color, width=2)
else:
# 头部
draw.ellipse([center-8, center-12, center+8, center+4], fill=fill_color)
# 身体
draw.rectangle([center-6, center+4, center+6, center+12], fill=fill_color)
return img
def main():
"""主函数"""
icon_dir = 'static/images/icons'
os.makedirs(icon_dir, exist_ok=True)
print("创建Material Design图标...")
for name in ICONS.keys():
# 创建轮廓图标
outline_img = create_material_icon(name, 'outline')
outline_path = os.path.join(icon_dir, f'{name}_outline.png')
outline_img.save(outline_path)
print(f"创建: {outline_path}")
# 创建填充图标
filled_img = create_material_icon(name, 'filled')
filled_path = os.path.join(icon_dir, f'{name}_filled.png')
filled_img.save(filled_path)
print(f"创建: {filled_path}")
print("✅ 图标创建完成!")
# 创建预览
create_preview(icon_dir)
def create_preview(icon_dir):
"""创建图标预览"""
html = """
<!DOCTYPE html>
<html>
<head>
<title>Material Design图标预览</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Roboto', sans-serif;
background: #F5F5F5;
color: #212121;
padding: 24px;
}
.container {
max-width: 800px;
margin: 0 auto;
background: #FFFFFF;
border-radius: 12px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
padding: 32px;
}
.header {
text-align: center;
margin-bottom: 32px;
padding-bottom: 24px;
border-bottom: 1px solid #EEEEEE;
}
.header h1 {
color: #6200EE;
font-size: 28px;
font-weight: 500;
margin-bottom: 8px;
}
.header p {
color: #757575;
font-size: 16px;
}
.icon-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 24px;
}
.icon-card {
background: #FAFAFA;
border-radius: 12px;
padding: 24px;
text-align: center;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.icon-card:hover {
transform: translateY(-4px);
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
.icon-preview {
display: flex;
justify-content: center;
gap: 16px;
margin-bottom: 16px;
}
.icon-outline, .icon-filled {
display: flex;
flex-direction: column;
align-items: center;
}
.icon-label {
font-size: 12px;
color: #757575;
margin-top: 8px;
}
.icon-name {
font-size: 16px;
font-weight: 500;
color: #212121;
margin-bottom: 8px;
}
.icon-desc {
font-size: 14px;
color: #616161;
line-height: 1.5;
}
.color-scheme {
display: flex;
gap: 16px;
margin-top: 32px;
padding-top: 24px;
border-top: 1px solid #EEEEEE;
}
.color-item {
display: flex;
align-items: center;
gap: 8px;
}
.color-box {
width: 24px;
height: 24px;
border-radius: 4px;
}
.color-text {
font-size: 14px;
color: #616161;
}
.footer {
text-align: center;
margin-top: 32px;
padding-top: 24px;
border-top: 1px solid #EEEEEE;
color: #9E9E9E;
font-size: 14px;
}
@media (max-width: 600px) {
.container {
padding: 16px;
}
.icon-grid {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Material Design图标</h1>
<p>玩Android应用底部导航图标</p>
</div>
<div class="icon-grid">
"""
icon_names = {
'home': '首页',
'apps': '项目',
'chat': '公众号',
'layers': '体系',
'person': '我的'
}
icon_descs = {
'home': '应用首页,展示最新文章和Banner',
'apps': '开源项目浏览和分类查看',
'chat': '技术公众号文章订阅',
'layers': '技术知识体系结构',
'person': '用户中心和个人设置'
}
for name, chinese in icon_names.items():
html += f"""
<div class="icon-card">
<div class="icon-name">{chinese}</div>
<div class="icon-preview">
<div class="icon-outline">
<img src="{name}_outline.png" alt="{name} outline" width="48" height="48">
<div class="icon-label">未选中</div>
</div>
<div class="icon-filled">
<img src="{name}_filled.png" alt="{name} filled" width="48" height="48">
<div class="icon-label">选中</div>
</div>
</div>
<div class="icon-desc">{icon_descs[name]}</div>
</div>
"""
html += """
</div>
<div class="color-scheme">
<div class="color-item">
<div class="color-box" style="background: #6200EE;"></div>
<div class="color-text">主色 (Primary)</div>
</div>
<div class="color-item">
<div class="color-box" style="background: #3700B3;"></div>
<div class="color-text">主色变体</div>
</div>
<div class="color-item">
<div class="color-box" style="background: #03DAC6;"></div>
<div class="color-text">次要色</div>
</div>
<div class="color-item">
<div class="color-box" style="background: #757575;"></div>
<div class="color-text">未选中状态</div>
</div>
</div>
<div class="footer">
<p>图标尺寸: 48×48像素 | 生成时间: 2026-03-17</p>
</div>
</div>
</body>
</html>
"""
preview_path = os.path.join(icon_dir, 'preview.html')
with open(preview_path, 'w', encoding='utf-8') as f:
f.write(html)
print(f"预览文件: {preview_path}")
if __name__ == '__main__':
main()