feat: DMG background with larger fonts and app design system
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 26 KiB |
@@ -1,10 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
生成 DMG 背景图 — 美家卡智影设计规范
|
||||
====================================
|
||||
|
||||
画布: 660 x 400 px
|
||||
风格: 与应用 UI 一致(绿色品牌色、卡片阴影、圆角)
|
||||
画布: 660 x 400 px(直接渲染,无缩放)
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
@@ -14,74 +11,75 @@ from PIL import Image, ImageDraw, ImageFont
|
||||
# ──────────────────────────── 配置 ────────────────────────────
|
||||
W, H = 660, 400
|
||||
|
||||
# 颜色(引用应用 CSS 变量)
|
||||
BG = (249, 250, 251) # --bg-main: #f9fafb
|
||||
CARD_BG = (255, 255, 255) # --bg-card: #fff
|
||||
PRIMARY = (54, 178, 106) # --primary: #36b26a
|
||||
TEXT_PRIMARY = (17, 24, 39) # --text-primary: #111827
|
||||
TEXT_SECONDARY = (107, 114, 128) # --text-secondary: #6b7280
|
||||
TEXT_TERTIARY = (156, 163, 175) # --text-tertiary: #9ca3af
|
||||
BORDER = (229, 231, 235) # --border-color: #e5e7eb
|
||||
SUCCESS = (16, 185, 129) # --success: #10b981
|
||||
|
||||
# 阴影(模拟 CSS box-shadow)
|
||||
def draw_card_shadow(draw, bbox, color=(0, 0, 0), alpha=0.05, blur=8):
|
||||
"""绘制卡片阴影"""
|
||||
x1, y1, x2, y2 = bbox
|
||||
for i in range(blur, 0, -1):
|
||||
a = int(alpha * 255 * (i / blur))
|
||||
offset = blur - i + 2
|
||||
draw.rounded_rectangle(
|
||||
[x1 - offset, y1 - offset + 2, x2 + offset, y2 + offset + 4],
|
||||
radius=12,
|
||||
fill=(0, 0, 0, a),
|
||||
)
|
||||
# 颜色
|
||||
BG = (249, 250, 251)
|
||||
CARD_BG = (255, 255, 255)
|
||||
PRIMARY = (54, 178, 106)
|
||||
SECONDARY = (24, 160, 138)
|
||||
TEXT_PRIMARY = (17, 24, 39)
|
||||
TEXT_SECONDARY = (107, 114, 128)
|
||||
TEXT_TERTIARY = (156, 163, 175)
|
||||
BORDER = (229, 231, 235)
|
||||
|
||||
# ──────────────────────────── 字体 ────────────────────────────
|
||||
def get_font(size, bold=False):
|
||||
"""获取中文字体"""
|
||||
result = subprocess.run(
|
||||
["fc-match", "-f", "%{file}", "PingFang SC"],
|
||||
capture_output=True, text=True
|
||||
)
|
||||
path = result.stdout.strip()
|
||||
if path and Path(path).exists():
|
||||
idx = 2 if bold else 0 # 常规/粗体索引
|
||||
idx = 2 if bold else 0
|
||||
return ImageFont.truetype(path, size, index=idx)
|
||||
return ImageFont.load_default()
|
||||
|
||||
font_title = get_font(22, bold=True)
|
||||
font_subtitle = get_font(13, bold=True)
|
||||
font_body = get_font(12)
|
||||
font_caption = get_font(10)
|
||||
font_title = get_font(20, bold=True)
|
||||
font_subtitle = get_font(16, bold=True)
|
||||
font_body = get_font(13)
|
||||
font_caption = get_font(11)
|
||||
|
||||
# ──────────────────────────── 画布 ────────────────────────────
|
||||
bg = Image.new("RGBA", (W, H), (*BG, 255))
|
||||
draw = ImageDraw.Draw(bg)
|
||||
|
||||
# ──────────────────────────── 顶部品牌区 ────────────────────────────
|
||||
# 加载 Logo(绿色 M)
|
||||
logo = Image.open("icons/icon.png").convert("RGBA")
|
||||
logo = Image.open("../public/assets/logo.png").convert("RGBA")
|
||||
logo_size = 36
|
||||
logo.thumbnail((logo_size, logo_size), Image.LANCZOS)
|
||||
|
||||
# 放置 Logo(顶部居中偏左,与文字搭配)
|
||||
logo_x = (W - logo_size) // 2 - 70
|
||||
logo_y = 28
|
||||
logo_x = (W - logo_size) // 2 - 65
|
||||
logo_y = 20
|
||||
bg.paste(logo, (logo_x, logo_y), logo)
|
||||
|
||||
# 品牌名称(品牌绿色)
|
||||
draw.text((logo_x + logo_size + 10, logo_y + 6), "美家卡智影",
|
||||
fill=PRIMARY, font=font_title)
|
||||
# 品牌名称 — 渐变文字效果(加宽 20px 防止截断)
|
||||
title_text = "美家卡智影"
|
||||
title_x = logo_x + logo_size + 8
|
||||
title_y = logo_y + 2
|
||||
|
||||
tw = int(draw.textlength(title_text, font=font_title)) + 30
|
||||
th = font_title.size + 8
|
||||
|
||||
gradient = Image.new("RGBA", (tw, th), (0, 0, 0, 0))
|
||||
for y in range(th):
|
||||
ratio = y / th
|
||||
r = int(PRIMARY[0] * (1 - ratio) + SECONDARY[0] * ratio)
|
||||
g = int(PRIMARY[1] * (1 - ratio) + SECONDARY[1] * ratio)
|
||||
b = int(PRIMARY[2] * (1 - ratio) + SECONDARY[2] * ratio)
|
||||
for x in range(tw):
|
||||
gradient.putpixel((x, y), (r, g, b, 255))
|
||||
|
||||
mask = Image.new("L", (tw, th), 0)
|
||||
mask_draw = ImageDraw.Draw(mask)
|
||||
mask_draw.text((0, 0), title_text, fill=255, font=font_title)
|
||||
|
||||
gradient.putalpha(mask)
|
||||
bg.paste(gradient, (title_x, title_y), gradient)
|
||||
|
||||
# ──────────────────────────── 中部拖拽引导 ────────────────────────────
|
||||
# 拖拽箭头(从左侧指向右侧)
|
||||
arrow_y = 195
|
||||
arrow_y = 200
|
||||
arrow_start = 220
|
||||
arrow_end = 440
|
||||
arrow_mid = (arrow_start + arrow_end) // 2
|
||||
|
||||
# 虚线箭头身
|
||||
dash_len = 6
|
||||
gap_len = 4
|
||||
current = arrow_start
|
||||
@@ -91,22 +89,20 @@ while current < arrow_end - 10:
|
||||
fill=PRIMARY, width=2)
|
||||
current += dash_len + gap_len
|
||||
|
||||
# 箭头头部
|
||||
draw.polygon([(arrow_end, arrow_y), (arrow_end - 8, arrow_y - 4),
|
||||
(arrow_end - 8, arrow_y + 4)], fill=PRIMARY)
|
||||
|
||||
# 引导文字
|
||||
draw.text((W // 2, arrow_y + 18), "将左侧图标拖拽到右侧 Applications 文件夹",
|
||||
draw.text((W // 2, arrow_y + 14), "将左侧图标拖拽到右侧 Applications 文件夹",
|
||||
fill=TEXT_SECONDARY, font=font_body, anchor="mm")
|
||||
|
||||
# ──────────────────────────── 底部提示卡片 ────────────────────────────
|
||||
card_w = 420
|
||||
card_h = 110
|
||||
card_w = 600
|
||||
card_h = 105
|
||||
card_x = (W - card_w) // 2
|
||||
card_y = 245
|
||||
card_y = 242
|
||||
radius = 12
|
||||
|
||||
# 卡片阴影(多层模拟)
|
||||
# 阴影
|
||||
shadow = Image.new("RGBA", (W, H), (0, 0, 0, 0))
|
||||
shadow_draw = ImageDraw.Draw(shadow)
|
||||
for i in range(6, 0, -1):
|
||||
@@ -126,15 +122,14 @@ draw.rounded_rectangle(
|
||||
radius=radius, fill=CARD_BG, outline=BORDER, width=1
|
||||
)
|
||||
|
||||
# 左侧绿色竖条(强调色)
|
||||
bar_w = 4
|
||||
# 左侧绿色竖条
|
||||
draw.rounded_rectangle(
|
||||
[card_x, card_y + 16, card_x + bar_w, card_y + card_h - 16],
|
||||
radius=bar_w // 2, fill=PRIMARY
|
||||
[card_x, card_y + 14, card_x + 3, card_y + card_h - 14],
|
||||
radius=1, fill=PRIMARY
|
||||
)
|
||||
|
||||
# 提示标题(绿色)
|
||||
draw.text((card_x + 20, card_y + 14), "首次安装提示",
|
||||
# 提示标题
|
||||
draw.text((card_x + 16, card_y + 12), "首次安装提示",
|
||||
fill=PRIMARY, font=font_subtitle)
|
||||
|
||||
# 提示正文
|
||||
@@ -143,14 +138,14 @@ tip_lines = [
|
||||
"请右键点击应用图标,选择「打开」,或在系统设置中允许",
|
||||
]
|
||||
for i, line in enumerate(tip_lines):
|
||||
draw.text((card_x + 20, card_y + 38 + i * 18), line,
|
||||
draw.text((card_x + 16, card_y + 36 + i * 20), line,
|
||||
fill=TEXT_SECONDARY, font=font_body)
|
||||
|
||||
# ──────────────────────────── 底部版本号 ────────────────────────────
|
||||
draw.text((W // 2, H - 16), "v1.5.18",
|
||||
draw.text((W // 2, H - 14), "v1.5.18",
|
||||
fill=TEXT_TERTIARY, font=font_caption, anchor="mm")
|
||||
|
||||
# ──────────────────────────── 保存 ────────────────────────────
|
||||
output = bg.convert("RGB")
|
||||
output.save("dmg-background.png", "PNG")
|
||||
print("✅ Generated: tauri-app/src-tauri/dmg-background.png (660x400)")
|
||||
print("✅ Generated: dmg-background.png (660x400)")
|
||||
|
||||
Reference in New Issue
Block a user