This commit is contained in:
Ubuntu
2026-07-03 16:58:28 +08:00
commit 32b43f85bd
6240 changed files with 1987678 additions and 0 deletions
@@ -0,0 +1,404 @@
#!/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()