Files
ctbjrj/tools/make_ribbon_icons_lucide.py

119 lines
4.5 KiB
Python

# -*- coding: utf-8 -*-
"""功能区 24 图标最终版:Lucide 开源图标库(ISC 可商用,专业设计)。
管线:jsdelivr 拉取 lucide-static SVG → 替换 currentColor 为语义色 → Edge 无头渲染 256px → 缩 64px。
文件名不变(bin\\Debug\\icons\\*.png),Designer.cs 的 FromFile 路径不用改。
404 的图标名会打印出来供换名重跑。"""
import io
import os
import re
import shutil
import subprocess
import tempfile
from PIL import Image
ROOT = r"C:\Users\099978\Documents\SharpDevelop Projects\成套报价软件"
PNG_DIR = os.path.join(ROOT, "成套报价软件", "bin", "Debug", "icons")
SVG_DIR = os.path.join(ROOT, "成套报价软件", "icons", "svg", "lucide")
EDGE = r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe"
VER = "0.525.0"
URL = "https://cdn.jsdelivr.net/npm/lucide-static@%s/icons/%%s.svg" % VER
INK = "#3D434A" # 墨青灰(默认)
GRN = "#217346" # 强调绿(=功能区 AccentColor)
COP = "#C8791E" # 铜橙
RED = "#D64541" # 警示红
BLU = "#2B579A" # 点缀蓝
# 按钮 → (lucide 图标名, 颜色)
BIND = {
"new-project": ("file-plus-2", INK),
"edit-project": ("file-pen", INK),
"delete-project": ("trash-2", RED),
"open-project": ("folder-open", INK),
"copy-project": ("files", INK),
"import-project": ("import", GRN),
"export-project": ("export", BLU),
"open-quote": ("folder-open", INK), # button9 同款
"edit-quote": ("file-pen", INK), # button10 同款
"save": ("save", GRN),
"import-quote": ("file-down", GRN),
"report": ("table-cells", INK),
"busbar": ("align-justify", COP), # 三横线=三根铜排
"factor": ("sliders-horizontal", INK),
"sort-components": ("arrow-up-narrow-wide", INK),
"template-cost": ("badge-japanese-yen", GRN),
"cad-grab": ("drafting-compass", INK),
"login": ("log-in", GRN),
"password": ("key-round", INK),
"member": ("id-card", INK),
"company": ("building-2", INK),
"save-layout": ("layout-template", INK),
"backup": ("database-backup", GRN),
"restore": ("archive-restore", INK),
}
def fetch(name):
import urllib.request
req = urllib.request.Request(URL % name, headers={"User-Agent": "Mozilla/5.0"})
with urllib.request.urlopen(req, timeout=30) as r:
return r.read().decode("utf-8")
def process(svg_text, color):
# 去注释/class,currentColor→语义色,尺寸改 256(viewBox 24 不动)
svg_text = re.sub(r"<!--.*?-->\s*", "", svg_text, flags=re.S)
svg_text = svg_text.replace('class="lucide lucide-%s"' % "", "")
svg_text = re.sub(r'\s+class="[^"]*"', "", svg_text)
svg_text = svg_text.replace('stroke="currentColor"', 'stroke="%s"' % color)
svg_text = svg_text.replace('width="24"', 'width="256"').replace('height="24"', 'height="256"')
return svg_text
def render_edge(name, svg_text):
sp = os.path.join(SVG_DIR, name + ".svg")
with io.open(sp, "w", encoding="utf-8") as f:
f.write(svg_text)
tmp = tempfile.mkdtemp(prefix="lucide_")
try:
tmp_svg = os.path.join(tmp, "i.svg")
tmp_png = os.path.join(tmp, "i.png")
shutil.copy(sp, tmp_svg)
subprocess.run(
[EDGE, "--headless", "--disable-gpu", "--no-sandbox",
"--user-data-dir=" + os.path.join(tmp, "p"),
"--screenshot=" + tmp_png, "--window-size=256,256",
"--default-background-color=00000000",
"file:///" + tmp_svg.replace("\\", "/")],
capture_output=True, timeout=40)
if not os.path.exists(tmp_png):
raise RuntimeError("Edge 渲染失败")
Image.open(tmp_png).convert("RGBA").resize((64, 64), Image.LANCZOS)\
.save(os.path.join(PNG_DIR, name + ".png"))
finally:
shutil.rmtree(tmp, ignore_errors=True)
def main():
os.makedirs(SVG_DIR, exist_ok=True)
os.makedirs(PNG_DIR, exist_ok=True)
ok, missing = 0, []
for name, (icon, color) in BIND.items():
try:
raw = fetch(icon)
if "<svg" not in raw:
raise RuntimeError("非 SVG 响应")
render_edge(name, process(raw, color))
ok += 1
print(" ✓ %-18s <- %s" % (name, icon))
except Exception as ex:
missing.append((name, icon, str(ex)[:80]))
print("\n完成 %d/%d" % (ok, len(BIND)))
for n, i, e in missing:
print(" [失败] %s <- %s: %s" % (n, i, e))
if __name__ == "__main__":
main()