refresh gitignore
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -24,7 +24,9 @@ node_modules
|
||||
|
||||
*.ttf
|
||||
frontend/vite.config.ts
|
||||
frontend/dist/fonts.json
|
||||
frontend/public/fonts.json
|
||||
miniprogram/assets/fonts.json
|
||||
|
||||
# secrets
|
||||
.env
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
|
||||
var u=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function a(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}function f(e){if(Object.prototype.hasOwnProperty.call(e,"__esModule"))return e;var n=e.default;if(typeof n=="function"){var t=function r(){var o=!1;try{o=this instanceof r}catch{}return o?Reflect.construct(n,arguments,this.constructor):n.apply(this,arguments)};t.prototype=n.prototype}else t={};return Object.defineProperty(t,"__esModule",{value:!0}),Object.keys(e).forEach(function(r){var o=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,o.get?o:{enumerable:!0,get:function(){return e[r]}})}),t}export{a,u as c,f as g};
|
||||
2
frontend/dist/assets/download-T9wchiI1.js
vendored
2
frontend/dist/assets/download-T9wchiI1.js
vendored
@@ -1,2 +0,0 @@
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/jszip.min-CRv3yS3R.js","assets/_commonjsHelpers-DsqdWQfm.js"])))=>i.map(i=>d[i]);
|
||||
import{_ as v}from"./index-CKp66E8b.js";function p(t,e,n="text/plain"){const o=new Blob([t],{type:n});s(o,e)}function s(t,e){const n=URL.createObjectURL(t),o=document.createElement("a");o.href=n,o.download=e,document.body.appendChild(o),o.click(),document.body.removeChild(o),URL.revokeObjectURL(n)}function P(t,e){p(t,e,"image/svg+xml")}async function F(t,e="font2svg-export.zip"){const n=(await v(async()=>{const{default:r}=await import("./jszip.min-CRv3yS3R.js").then(i=>i.j);return{default:r}},__vite__mapDeps([0,1]))).default,o=new n;for(const r of t)o.file(r.name,r.content);const a=await o.generateAsync({type:"blob"});s(a,e)}function d(t){if(!t)return null;const e=t.match(/-?\d+(\.\d+)?/);if(!e)return null;const n=Number(e[0]);return Number.isFinite(n)?n:null}function x(t){const n=new DOMParser().parseFromString(t,"image/svg+xml").documentElement,o=d(n.getAttribute("width")),a=d(n.getAttribute("height"));if(o&&a)return{width:o,height:a};const r=n.getAttribute("viewBox");if(r){const i=r.trim().split(/[\s,]+/).map(Number);if(i.length===4&&Number.isFinite(i[2])&&Number.isFinite(i[3]))return{width:Math.max(1,i[2]),height:Math.max(1,i[3])}}return{width:1024,height:1024}}async function _(t,e){const n=x(t),o=e?.scale??1,a=Math.max(1,Math.round((e?.width??n.width)*o)),r=Math.max(1,Math.round((e?.height??n.height)*o)),i=document.createElement("canvas");i.width=a,i.height=r;const l=i.getContext("2d");if(!l)throw new Error("无法创建 PNG 画布");e?.backgroundColor?(l.fillStyle=e.backgroundColor,l.fillRect(0,0,a,r)):l.clearRect(0,0,a,r);const f=new Blob([t],{type:"image/svg+xml;charset=utf-8"}),u=URL.createObjectURL(f);try{const c=new Image;await new Promise((w,b)=>{c.onload=()=>w(),c.onerror=()=>b(new Error("SVG 转 PNG 失败")),c.src=u}),l.drawImage(c,0,0,a,r)}finally{URL.revokeObjectURL(u)}const g=await new Promise(c=>{i.toBlob(c,"image/png")});if(!g)throw new Error("PNG 编码失败");return g}async function R(t,e,n){const o=await _(t,n);s(o,e)}function m(t){return t.replace(/[<>:"/\\|?*\x00-\x1F]/g,"_").replace(/\s+/g,"_").substring(0,200)}function h(t,e){const n=m(Array.from(t).slice(0,8).join(""));return`${m(e.substring(0,20))}_${n}`}function B(t,e){return`${h(t,e)}.svg`}function L(t,e){return`${h(t,e)}.png`}export{_ as convertSvgToPngBlob,s as downloadBlob,F as downloadMultipleFiles,R as downloadPngFromSvg,P as downloadSvg,p as downloadText,L as generatePngFilename,B as generateSvgFilename,m as sanitizeFilename};
|
||||
1
frontend/dist/assets/hb-C3piUv6a.js
vendored
1
frontend/dist/assets/hb-C3piUv6a.js
vendored
File diff suppressed because one or more lines are too long
1
frontend/dist/assets/hbjs-B2Ncxvef.js
vendored
1
frontend/dist/assets/hbjs-B2Ncxvef.js
vendored
File diff suppressed because one or more lines are too long
18
frontend/dist/assets/index-CKp66E8b.js
vendored
18
frontend/dist/assets/index-CKp66E8b.js
vendored
File diff suppressed because one or more lines are too long
1
frontend/dist/assets/index-DQpT4mud.css
vendored
1
frontend/dist/assets/index-DQpT4mud.css
vendored
File diff suppressed because one or more lines are too long
2
frontend/dist/assets/jszip.min-CRv3yS3R.js
vendored
2
frontend/dist/assets/jszip.min-CRv3yS3R.js
vendored
File diff suppressed because one or more lines are too long
9
frontend/dist/assets/webicon-K25S575h.svg
vendored
9
frontend/dist/assets/webicon-K25S575h.svg
vendored
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 170 KiB |
11
frontend/dist/default.json
vendored
11
frontend/dist/default.json
vendored
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"inputText": "星程字体转换",
|
||||
"fontSize": 50,
|
||||
"textColor": "#dc2626",
|
||||
"selectedFontIds": [
|
||||
"0001"
|
||||
],
|
||||
"favoriteFontIds": [
|
||||
"0001"
|
||||
]
|
||||
}
|
||||
BIN
frontend/dist/favicon.png
vendored
BIN
frontend/dist/favicon.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 59 KiB |
9
frontend/dist/favicon.svg
vendored
9
frontend/dist/favicon.svg
vendored
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 170 KiB |
BIN
frontend/dist/favicon_new.png
vendored
BIN
frontend/dist/favicon_new.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 33 KiB |
170
frontend/dist/fonts.json
vendored
170
frontend/dist/fonts.json
vendored
@@ -1,170 +0,0 @@
|
||||
[
|
||||
{
|
||||
"id": "0001",
|
||||
"name": "AlimamaDaoLiTi",
|
||||
"filename": "AlimamaDaoLiTi.ttf",
|
||||
"category": "其他字体",
|
||||
"path": "/fonts/其他字体/AlimamaDaoLiTi.ttf"
|
||||
},
|
||||
{
|
||||
"id": "0002",
|
||||
"name": "Hangeuljaemin4-Regular",
|
||||
"filename": "Hangeuljaemin4-Regular.ttf",
|
||||
"category": "其他字体",
|
||||
"path": "/fonts/其他字体/Hangeuljaemin4-Regular.ttf"
|
||||
},
|
||||
{
|
||||
"id": "0003",
|
||||
"name": "I.顏體",
|
||||
"filename": "I.顏體.ttf",
|
||||
"category": "其他字体",
|
||||
"path": "/fonts/其他字体/I.顏體.ttf"
|
||||
},
|
||||
{
|
||||
"id": "0004",
|
||||
"name": "XCDUANZHUANGSONGTI",
|
||||
"filename": "XCDUANZHUANGSONGTI.ttf",
|
||||
"category": "其他字体",
|
||||
"path": "/fonts/其他字体/XCDUANZHUANGSONGTI.ttf"
|
||||
},
|
||||
{
|
||||
"id": "0005",
|
||||
"name": "qiji-combo",
|
||||
"filename": "qiji-combo.ttf",
|
||||
"category": "其他字体",
|
||||
"path": "/fonts/其他字体/qiji-combo.ttf"
|
||||
},
|
||||
{
|
||||
"id": "0006",
|
||||
"name": "临海隶书",
|
||||
"filename": "临海隶书.ttf",
|
||||
"category": "其他字体",
|
||||
"path": "/fonts/其他字体/临海隶书.ttf"
|
||||
},
|
||||
{
|
||||
"id": "0007",
|
||||
"name": "京華老宋体_KingHwa_OldSong",
|
||||
"filename": "京華老宋体_KingHwa_OldSong.ttf",
|
||||
"category": "其他字体",
|
||||
"path": "/fonts/其他字体/京華老宋体_KingHwa_OldSong.ttf"
|
||||
},
|
||||
{
|
||||
"id": "0008",
|
||||
"name": "优设标题黑",
|
||||
"filename": "优设标题黑.ttf",
|
||||
"category": "其他字体",
|
||||
"path": "/fonts/其他字体/优设标题黑.ttf"
|
||||
},
|
||||
{
|
||||
"id": "0009",
|
||||
"name": "包图小白体",
|
||||
"filename": "包图小白体.ttf",
|
||||
"category": "其他字体",
|
||||
"path": "/fonts/其他字体/包图小白体.ttf"
|
||||
},
|
||||
{
|
||||
"id": "0010",
|
||||
"name": "源界明朝",
|
||||
"filename": "源界明朝.ttf",
|
||||
"category": "其他字体",
|
||||
"path": "/fonts/其他字体/源界明朝.ttf"
|
||||
},
|
||||
{
|
||||
"id": "0011",
|
||||
"name": "演示佛系体",
|
||||
"filename": "演示佛系体.ttf",
|
||||
"category": "其他字体",
|
||||
"path": "/fonts/其他字体/演示佛系体.ttf"
|
||||
},
|
||||
{
|
||||
"id": "0012",
|
||||
"name": "站酷快乐体",
|
||||
"filename": "站酷快乐体.ttf",
|
||||
"category": "其他字体",
|
||||
"path": "/fonts/其他字体/站酷快乐体.ttf"
|
||||
},
|
||||
{
|
||||
"id": "0013",
|
||||
"name": "问藏书房",
|
||||
"filename": "问藏书房.ttf",
|
||||
"category": "其他字体",
|
||||
"path": "/fonts/其他字体/问藏书房.ttf"
|
||||
},
|
||||
{
|
||||
"id": "0014",
|
||||
"name": "霞鹜臻楷",
|
||||
"filename": "霞鹜臻楷.ttf",
|
||||
"category": "其他字体",
|
||||
"path": "/fonts/其他字体/霞鹜臻楷.ttf"
|
||||
},
|
||||
{
|
||||
"id": "0015",
|
||||
"name": "庞门正道标题体",
|
||||
"filename": "庞门正道标题体.ttf",
|
||||
"category": "庞门正道",
|
||||
"path": "/fonts/庞门正道/庞门正道标题体.ttf"
|
||||
},
|
||||
{
|
||||
"id": "0016",
|
||||
"name": "庞门正道标题体",
|
||||
"filename": "庞门正道标题体.ttf",
|
||||
"category": "庞门正道-测试",
|
||||
"path": "/fonts/庞门正道-测试/庞门正道标题体.ttf"
|
||||
},
|
||||
{
|
||||
"id": "0017",
|
||||
"name": "王漢宗勘亭流繁",
|
||||
"filename": "王漢宗勘亭流繁.ttf",
|
||||
"category": "王漢宗",
|
||||
"path": "/fonts/王漢宗/王漢宗勘亭流繁.ttf"
|
||||
},
|
||||
{
|
||||
"id": "0018",
|
||||
"name": "王漢宗新潮體",
|
||||
"filename": "王漢宗新潮體.ttf",
|
||||
"category": "王漢宗",
|
||||
"path": "/fonts/王漢宗/王漢宗新潮體.ttf"
|
||||
},
|
||||
{
|
||||
"id": "0019",
|
||||
"name": "王漢宗波卡體空陰",
|
||||
"filename": "王漢宗波卡體空陰.ttf",
|
||||
"category": "王漢宗",
|
||||
"path": "/fonts/王漢宗/王漢宗波卡體空陰.ttf"
|
||||
},
|
||||
{
|
||||
"id": "0020",
|
||||
"name": "王漢宗細黑體繁",
|
||||
"filename": "王漢宗細黑體繁.ttf",
|
||||
"category": "王漢宗",
|
||||
"path": "/fonts/王漢宗/王漢宗細黑體繁.ttf"
|
||||
},
|
||||
{
|
||||
"id": "0021",
|
||||
"name": "王漢宗綜藝體雙空陰",
|
||||
"filename": "王漢宗綜藝體雙空陰.ttf",
|
||||
"category": "王漢宗",
|
||||
"path": "/fonts/王漢宗/王漢宗綜藝體雙空陰.ttf"
|
||||
},
|
||||
{
|
||||
"id": "0022",
|
||||
"name": "王漢宗超明體繁",
|
||||
"filename": "王漢宗超明體繁.ttf",
|
||||
"category": "王漢宗",
|
||||
"path": "/fonts/王漢宗/王漢宗超明體繁.ttf"
|
||||
},
|
||||
{
|
||||
"id": "0023",
|
||||
"name": "王漢宗酷儷海報",
|
||||
"filename": "王漢宗酷儷海報.ttf",
|
||||
"category": "王漢宗",
|
||||
"path": "/fonts/王漢宗/王漢宗酷儷海報.ttf"
|
||||
},
|
||||
{
|
||||
"id": "0024",
|
||||
"name": "王漢宗顏楷體繁",
|
||||
"filename": "王漢宗顏楷體繁.ttf",
|
||||
"category": "王漢宗",
|
||||
"path": "/fonts/王漢宗/王漢宗顏楷體繁.ttf"
|
||||
}
|
||||
]
|
||||
17
frontend/dist/index.html
vendored
17
frontend/dist/index.html
vendored
@@ -1,17 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<!-- 统一使用 favicon_new.png 作为站点图标,避免 Safari 继续优先采用 SVG 或 mask 图标 -->
|
||||
<link rel="icon" type="image/png" href="/favicon_new.png" />
|
||||
<link rel="shortcut icon" href="/favicon_new.png" />
|
||||
<link rel="apple-touch-icon" href="/favicon_new.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Font2SVG - 字体转SVG工具</title>
|
||||
<script type="module" crossorigin src="/assets/index-CKp66E8b.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-DQpT4mud.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
376
scripts/font-id-state.json
Normal file
376
scripts/font-id-state.json
Normal file
@@ -0,0 +1,376 @@
|
||||
{
|
||||
"version": 1,
|
||||
"nextId": 370,
|
||||
"pathToId": {
|
||||
"上首造字/No.1-上首锐博体.ttf": "0001",
|
||||
"上首造字/No.10-上首叮当体.ttf": "0002",
|
||||
"上首造字/No.100-上首纤宋体.ttf": "0003",
|
||||
"上首造字/No.101-上首武士黑体.ttf": "0004",
|
||||
"上首造字/No.102-上首玄藏体.ttf": "0005",
|
||||
"上首造字/No.103-上首星际体.ttf": "0006",
|
||||
"上首造字/No.104-上首鸿志手写体.ttf": "0007",
|
||||
"上首造字/No.105-上首逍遥体.ttf": "0008",
|
||||
"上首造字/No.106-上首简墨体.ttf": "0009",
|
||||
"上首造字/No.107-上首松羽体.ttf": "0010",
|
||||
"上首造字/No.108-上首燕尾体.ttf": "0011",
|
||||
"上首造字/No.109-上首韶华体.ttf": "0012",
|
||||
"上首造字/No.11-上首车车体.ttf": "0013",
|
||||
"上首造字/No.110-上首烈宋体.ttf": "0014",
|
||||
"上首造字/No.111-上首方舟体.ttf": "0015",
|
||||
"上首造字/No.112-上首壹方体.ttf": "0016",
|
||||
"上首造字/No.113-上首轩正体.ttf": "0017",
|
||||
"上首造字/No.114-上首长城体.ttf": "0018",
|
||||
"上首造字/No.115-上首音符体.ttf": "0019",
|
||||
"上首造字/No.116-上首如意体.ttf": "0020",
|
||||
"上首造字/No.117-上首酷峰体.ttf": "0021",
|
||||
"上首造字/No.118-上首星耀体.ttf": "0022",
|
||||
"上首造字/No.119-上首罗马体.ttf": "0023",
|
||||
"上首造字/No.12-上首秀圆体.ttf": "0024",
|
||||
"上首造字/No.120-上首宽言体.ttf": "0025",
|
||||
"上首造字/No.121-上首刻宋体.ttf": "0026",
|
||||
"上首造字/No.122-上首云润体.ttf": "0027",
|
||||
"上首造字/No.123-上首方义手刷体.ttf": "0028",
|
||||
"上首造字/No.124-上首艺圆体.ttf": "0029",
|
||||
"上首造字/No.125-上首方尊体.ttf": "0030",
|
||||
"上首造字/No.126-上首吉言体.ttf": "0031",
|
||||
"上首造字/No.127-上首简一体.ttf": "0032",
|
||||
"上首造字/No.128-上首玄黑体.ttf": "0033",
|
||||
"上首造字/No.129-上首墨遥体.ttf": "0034",
|
||||
"上首造字/No.13-上首华凤书法体.ttf": "0035",
|
||||
"上首造字/No.130-上首追光手写体.ttf": "0036",
|
||||
"上首造字/No.131-上首斗金体.ttf": "0037",
|
||||
"上首造字/No.132-上首豆干体.ttf": "0038",
|
||||
"上首造字/No.133-上首魔法体.ttf": "0039",
|
||||
"上首造字/No.134-上首文化体.ttf": "0040",
|
||||
"上首造字/No.135-上首龙吟体.ttf": "0041",
|
||||
"上首造字/No.136-上首悠然体.ttf": "0042",
|
||||
"上首造字/No.137-上首本草纲目体.ttf": "0043",
|
||||
"上首造字/No.138-上首星斗体.ttf": "0044",
|
||||
"上首造字/No.139-上首鼎宋体.ttf": "0045",
|
||||
"上首造字/No.14-上首水滴体.ttf": "0046",
|
||||
"上首造字/No.140-上首妖刀体.ttf": "0047",
|
||||
"上首造字/No.141-上首高达体.ttf": "0048",
|
||||
"上首造字/No.142-上首综艺体.ttf": "0049",
|
||||
"上首造字/No.143-上首圆木体.ttf": "0050",
|
||||
"上首造字/No.144-上首逍遥书法体.ttf": "0051",
|
||||
"上首造字/No.145-上首高光体.ttf": "0052",
|
||||
"上首造字/No.146-上首清雅宋体.ttf": "0053",
|
||||
"上首造字/No.147-上首云隶体.ttf": "0054",
|
||||
"上首造字/No.148-上首标榜体.ttf": "0055",
|
||||
"上首造字/No.149-上首奶酪体.ttf": "0056",
|
||||
"上首造字/No.15-上首润黑体.ttf": "0057",
|
||||
"上首造字/No.150-上首秋刀体.ttf": "0058",
|
||||
"上首造字/No.151-上首凤鸣体.ttf": "0059",
|
||||
"上首造字/No.152-上首南枝体.ttf": "0060",
|
||||
"上首造字/No.152上首南枝体.ttf": "0061",
|
||||
"上首造字/No.153-上首可乐体.ttf": "0062",
|
||||
"上首造字/No.154-上首长青体.ttf": "0063",
|
||||
"上首造字/No.155-上首中正宋体.ttf": "0064",
|
||||
"上首造字/No.156-上首曲奇体.ttf": "0065",
|
||||
"上首造字/No.157-上首萌萌手写体.ttf": "0066",
|
||||
"上首造字/No.158-上首朗润体.ttf": "0067",
|
||||
"上首造字/No.159-上首财神体.ttf": "0068",
|
||||
"上首造字/No.16-上首锐圆体.ttf": "0069",
|
||||
"上首造字/No.160-上首混沌体.ttf": "0070",
|
||||
"上首造字/No.161-上首刺云体.ttf": "0071",
|
||||
"上首造字/No.162-上首幻视体.ttf": "0072",
|
||||
"上首造字/No.163-上首万象体.ttf": "0073",
|
||||
"上首造字/No.164-上首简正体.ttf": "0074",
|
||||
"上首造字/No.165-上首刺秦体.ttf": "0075",
|
||||
"上首造字/No.166-上首暗黑体.ttf": "0076",
|
||||
"上首造字/No.167-上首萌虎体.ttf": "0077",
|
||||
"上首造字/No.168-上首雪糕体.ttf": "0078",
|
||||
"上首造字/No.169-上首逐浪书法体.ttf": "0079",
|
||||
"上首造字/No.17-上首钝黑体.ttf": "0080",
|
||||
"上首造字/No.170-上首方玉体.ttf": "0081",
|
||||
"上首造字/No.171-上首龙猫体.ttf": "0082",
|
||||
"上首造字/No.172-上首木兰体.ttf": "0083",
|
||||
"上首造字/No.173-上首山水宋体.ttf": "0084",
|
||||
"上首造字/No.174-上首扑克体.ttf": "0085",
|
||||
"上首造字/No.175-上首潮玩体.ttf": "0086",
|
||||
"上首造字/No.176-上首鲁班宋体.ttf": "0087",
|
||||
"上首造字/No.177-上首奶糖体.ttf": "0088",
|
||||
"上首造字/No.178-上首浓墨体.ttf": "0089",
|
||||
"上首造字/No.179-上首朋克体.ttf": "0090",
|
||||
"上首造字/No.18-上首疾风书法体.ttf": "0091",
|
||||
"上首造字/No.180-上首风云书法体.ttf": "0092",
|
||||
"上首造字/No.181-上首未来体.ttf": "0093",
|
||||
"上首造字/No.182-上首象牙体.ttf": "0094",
|
||||
"上首造字/No.183-上首悦圆体.ttf": "0095",
|
||||
"上首造字/No.184-上首月牙体.ttf": "0096",
|
||||
"上首造字/No.185-上首矩正体.ttf": "0097",
|
||||
"上首造字/No.186-上首鸿运体.ttf": "0098",
|
||||
"上首造字/No.187-上首童年体.ttf": "0099",
|
||||
"上首造字/No.188-上首凌宋体.ttf": "0100",
|
||||
"上首造字/No.189-上首品黑体.ttf": "0101",
|
||||
"上首造字/No.19-上首简黑极细体.ttf": "0102",
|
||||
"上首造字/No.190-上首波波手写体.ttf": "0103",
|
||||
"上首造字/No.191-上首祥瑞体.ttf": "0104",
|
||||
"上首造字/No.192-上首傲骨体.ttf": "0105",
|
||||
"上首造字/No.193-上首轩隶体.ttf": "0106",
|
||||
"上首造字/No.194-上首品宋体.ttf": "0107",
|
||||
"上首造字/No.195-上首金枝体.ttf": "0108",
|
||||
"上首造字/No.196-上首游龙体.ttf": "0109",
|
||||
"上首造字/No.197-上首魔方体.ttf": "0110",
|
||||
"上首造字/No.198-上首呆呆体.ttf": "0111",
|
||||
"上首造字/No.199-上首新潮体.ttf": "0112",
|
||||
"上首造字/No.2-上首维黑体.ttf": "0113",
|
||||
"上首造字/No.20-上首简宋纤细体.ttf": "0114",
|
||||
"上首造字/No.200-上首博雅体.ttf": "0115",
|
||||
"上首造字/No.201-上首鹊桥体.ttf": "0116",
|
||||
"上首造字/No.202-上首雅倩体.ttf": "0117",
|
||||
"上首造字/No.203-上首祥瑞手写体.ttf": "0118",
|
||||
"上首造字/No.204-上首茶颜体.ttf": "0119",
|
||||
"上首造字/No.205-上首羽刃体.ttf": "0120",
|
||||
"上首造字/No.206-上首幻灵体.ttf": "0121",
|
||||
"上首造字/No.207-上首西游体.ttf": "0122",
|
||||
"上首造字/No.208-上首古居体.ttf": "0123",
|
||||
"上首造字/No.209-上首润泽体.ttf": "0124",
|
||||
"上首造字/No.21-上首传奇书法体.ttf": "0125",
|
||||
"上首造字/No.210-上首醒狮体.ttf": "0126",
|
||||
"上首造字/No.211-上首冰刃体.ttf": "0127",
|
||||
"上首造字/No.212-上首玄武体.ttf": "0128",
|
||||
"上首造字/No.213-上首雪兔体.ttf": "0129",
|
||||
"上首造字/No.214-上首朱雀体.ttf": "0130",
|
||||
"上首造字/No.215-上首朗月体.ttf": "0131",
|
||||
"上首造字/No.216-上首招财猫体.ttf": "0132",
|
||||
"上首造字/No.217-上首星舰体.ttf": "0133",
|
||||
"上首造字/No.218-上首正舟体.ttf": "0134",
|
||||
"上首造字/No.219-上首白虎书法体.ttf": "0135",
|
||||
"上首造字/No.22-上首简圆体.ttf": "0136",
|
||||
"上首造字/No.220-上首梧桐体.ttf": "0137",
|
||||
"上首造字/No.221-上首标题体.ttf": "0138",
|
||||
"上首造字/No.222-上首阿呆体.ttf": "0139",
|
||||
"上首造字/No.223-上首月兔体.ttf": "0140",
|
||||
"上首造字/No.224-上首绫黑体.ttf": "0141",
|
||||
"上首造字/No.225-上首福禄体.ttf": "0142",
|
||||
"上首造字/No.226-上首机甲体.ttf": "0143",
|
||||
"上首造字/No.227-上首晴竹体.ttf": "0144",
|
||||
"上首造字/No.228-上首光折体.ttf": "0145",
|
||||
"上首造字/No.229-上首时光体.ttf": "0146",
|
||||
"上首造字/No.23-上首布丁体.ttf": "0147",
|
||||
"上首造字/No.230-上首胖虎体.ttf": "0148",
|
||||
"上首造字/No.231-上首奇妙体.ttf": "0149",
|
||||
"上首造字/No.232-上首龙腾体.ttf": "0150",
|
||||
"上首造字/No.233-上首怪兽体.ttf": "0151",
|
||||
"上首造字/No.234-上首极限体.ttf": "0152",
|
||||
"上首造字/No.235-上首御风书法体.ttf": "0153",
|
||||
"上首造字/No.236-上首东坡体.ttf": "0154",
|
||||
"上首造字/No.237-上首木鱼体.ttf": "0155",
|
||||
"上首造字/No.238-上首妙趣体.ttf": "0156",
|
||||
"上首造字/No.239-上首青云体.ttf": "0157",
|
||||
"上首造字/No.24-上首软糖体.ttf": "0158",
|
||||
"上首造字/No.240-上首雅隶体.ttf": "0159",
|
||||
"上首造字/No.241-上首蔷薇体.ttf": "0160",
|
||||
"上首造字/No.242-上首海浪体.ttf": "0161",
|
||||
"上首造字/No.243-上首青柏体.ttf": "0162",
|
||||
"上首造字/No.244-上首墩墩体.ttf": "0163",
|
||||
"上首造字/No.245-上首无限体.ttf": "0164",
|
||||
"上首造字/No.246-上首本墨体.ttf": "0165",
|
||||
"上首造字/No.247-上首祥云体.ttf": "0166",
|
||||
"上首造字/No.248-上首非凡体.ttf": "0167",
|
||||
"上首造字/No.249-上首市井体.ttf": "0168",
|
||||
"上首造字/No.25-上首锐圆极细体.ttf": "0169",
|
||||
"上首造字/No.250-上首松柏体.ttf": "0170",
|
||||
"上首造字/No.251-上首水波体.ttf": "0171",
|
||||
"上首造字/No.252-上首大头手写体.ttf": "0172",
|
||||
"上首造字/No.253-上首银蛇体.ttf": "0173",
|
||||
"上首造字/No.254-上首琥珀体.ttf": "0174",
|
||||
"上首造字/No.255-上首敦煌隶书体.ttf": "0175",
|
||||
"上首造字/No.256-上首楼兰体.ttf": "0176",
|
||||
"上首造字/No.257-上首福袋体.ttf": "0177",
|
||||
"上首造字/No.258-上首惊鸿体.ttf": "0178",
|
||||
"上首造字/No.259-上首果冻体.ttf": "0179",
|
||||
"上首造字/No.26-上首悦风体.ttf": "0180",
|
||||
"上首造字/No.260-上首山岳体.ttf": "0181",
|
||||
"上首造字/No.261-上首惊云体.ttf": "0182",
|
||||
"上首造字/No.262-上首江南宋体.ttf": "0183",
|
||||
"上首造字/No.263-上首蜡笔体.ttf": "0184",
|
||||
"上首造字/No.264-上首赛博体.ttf": "0185",
|
||||
"上首造字/No.265-上首心动体.ttf": "0186",
|
||||
"上首造字/No.266-上首千禧体.ttf": "0187",
|
||||
"上首造字/No.267-上首柔黑体.ttf": "0188",
|
||||
"上首造字/No.268-上首黑仪体.ttf": "0189",
|
||||
"上首造字/No.269-上首涂鸦体.ttf": "0190",
|
||||
"上首造字/No.27-上首锐棱体.ttf": "0191",
|
||||
"上首造字/No.270-上首天坛体.ttf": "0192",
|
||||
"上首造字/No.271-上首麒麟体.ttf": "0193",
|
||||
"上首造字/No.272-上首青瓦体.ttf": "0194",
|
||||
"上首造字/No.273-上首风云体.ttf": "0195",
|
||||
"上首造字/No.274-上首战魂体.ttf": "0196",
|
||||
"上首造字/No.275-上首招福体.ttf": "0197",
|
||||
"上首造字/No.276-上首佛陀体.ttf": "0198",
|
||||
"上首造字/No.277-上首大漠体.ttf": "0199",
|
||||
"上首造字/No.278-上首绘梦体.ttf": "0200",
|
||||
"上首造字/No.279-上首东方体.ttf": "0201",
|
||||
"上首造字/No.28-上首星岩体.ttf": "0202",
|
||||
"上首造字/No.280-上首英雄体.ttf": "0203",
|
||||
"上首造字/No.281-上首破冰体.ttf": "0204",
|
||||
"上首造字/No.282-上首玄机体.ttf": "0205",
|
||||
"上首造字/No.283-上首舞狮体.ttf": "0206",
|
||||
"上首造字/No.284-上首北斗体.ttf": "0207",
|
||||
"上首造字/No.285-上首万福体.ttf": "0208",
|
||||
"上首造字/No.286-上首云木体.ttf": "0209",
|
||||
"上首造字/No.287-上首方印体.ttf": "0210",
|
||||
"上首造字/No.288-上首几何体.ttf": "0211",
|
||||
"上首造字/No.289-上首江湖书法体.ttf": "0212",
|
||||
"上首造字/No.29-上首先锋体.ttf": "0213",
|
||||
"上首造字/No.290-上首书印体.ttf": "0214",
|
||||
"上首造字/No.291-上首淘气体.ttf": "0215",
|
||||
"上首造字/No.292-上首暗格体.ttf": "0216",
|
||||
"上首造字/No.293-上首逸尘体.ttf": "0217",
|
||||
"上首造字/No.294-上首小新体.ttf": "0218",
|
||||
"上首造字/No.295-上首荒原体.ttf": "0219",
|
||||
"上首造字/No.296-上首松针体.ttf": "0220",
|
||||
"上首造字/No.297-上首墨玄体.ttf": "0221",
|
||||
"上首造字/No.298-上首沧海书法体.ttf": "0222",
|
||||
"上首造字/No.299-上首王朝体.ttf": "0223",
|
||||
"上首造字/No.3-上首方圆体.ttf": "0224",
|
||||
"上首造字/No.30-上首倾城体.ttf": "0225",
|
||||
"上首造字/No.300-上首古皇体.ttf": "0226",
|
||||
"上首造字/No.301-上首言亭体.ttf": "0227",
|
||||
"上首造字/No.302-上首流金体.ttf": "0228",
|
||||
"上首造字/No.303-上首墨宋体.ttf": "0229",
|
||||
"上首造字/No.304-上首龙虎体.ttf": "0230",
|
||||
"上首造字/No.305-上首点墨体.ttf": "0231",
|
||||
"上首造字/No.306-上首万圣体.ttf": "0232",
|
||||
"上首造字/No.307-上首润元体.ttf": "0233",
|
||||
"上首造字/No.308-上首极速体.ttf": "0234",
|
||||
"上首造字/No.309-上首栏栅体.ttf": "0235",
|
||||
"上首造字/No.31-上首简黑纤细体.ttf": "0236",
|
||||
"上首造字/No.310-上首浮华体.ttf": "0237",
|
||||
"上首造字/No.311-上首梦想体.ttf": "0238",
|
||||
"上首造字/No.312-上首诗宋体.ttf": "0239",
|
||||
"上首造字/No.313-上首亦方体.ttf": "0240",
|
||||
"上首造字/No.314-上首心愿体.ttf": "0241",
|
||||
"上首造字/No.315-上首西施体.ttf": "0242",
|
||||
"上首造字/No.316-上首国美体.ttf": "0243",
|
||||
"上首造字/No.317-上首润玉体.ttf": "0244",
|
||||
"上首造字/No.318-上首炫酷体.ttf": "0245",
|
||||
"上首造字/No.319-上首云烟体.ttf": "0246",
|
||||
"上首造字/No.32-上首芊芊体.ttf": "0247",
|
||||
"上首造字/No.320-上首蜀汉体.ttf": "0248",
|
||||
"上首造字/No.321-上首盛唐体.ttf": "0249",
|
||||
"上首造字/No.322-上首折扇体.ttf": "0250",
|
||||
"上首造字/No.323-上首青竹体.ttf": "0251",
|
||||
"上首造字/No.324-上首胭脂体.ttf": "0252",
|
||||
"上首造字/No.33-上首方糖体.ttf": "0253",
|
||||
"上首造字/No.34-上首简黑中细体.ttf": "0254",
|
||||
"上首造字/No.35-上首积木体.ttf": "0255",
|
||||
"上首造字/No.36-上首金牛体.ttf": "0256",
|
||||
"上首造字/No.37-上首朗倩体.ttf": "0257",
|
||||
"上首造字/No.38-上首漠云体.ttf": "0258",
|
||||
"上首造字/No.39-上首至尊书法体.ttf": "0259",
|
||||
"上首造字/No.4-上首秀黑体.ttf": "0260",
|
||||
"上首造字/No.40-上首星芒体.ttf": "0261",
|
||||
"上首造字/No.41-上首山川体.ttf": "0262",
|
||||
"上首造字/No.42-上首芋圆体.ttf": "0263",
|
||||
"上首造字/No.43-上首星辰体.ttf": "0264",
|
||||
"上首造字/No.44-上首哥特体.ttf": "0265",
|
||||
"上首造字/No.45-上首黑岩体 .ttf": "0266",
|
||||
"上首造字/No.46-上首言黑体.ttf": "0267",
|
||||
"上首造字/No.47-上首御宋体.ttf": "0268",
|
||||
"上首造字/No.48-上首三国体.ttf": "0269",
|
||||
"上首造字/No.49-上首熊猫体.ttf": "0270",
|
||||
"上首造字/No.5-上首时尚体.ttf": "0271",
|
||||
"上首造字/No.50-上首国潮体.ttf": "0272",
|
||||
"上首造字/No.51-上首酷方体.ttf": "0273",
|
||||
"上首造字/No.52-上首碑楷体.ttf": "0274",
|
||||
"上首造字/No.53-上首逸飞体.ttf": "0275",
|
||||
"上首造字/No.54-上首少年体.ttf": "0276",
|
||||
"上首造字/No.55-上首锋芒体.ttf": "0277",
|
||||
"上首造字/No.56-上首新艺体.ttf": "0278",
|
||||
"上首造字/No.57-上首嘉木体.ttf": "0279",
|
||||
"上首造字/No.58-上首力方体.ttf": "0280",
|
||||
"上首造字/No.59-上首折言体.ttf": "0281",
|
||||
"上首造字/No.6-上首宽窄体.ttf": "0282",
|
||||
"上首造字/No.60-上首本刻体.ttf": "0283",
|
||||
"上首造字/No.61-上首古宋体.ttf": "0284",
|
||||
"上首造字/No.62-上首黑风体.ttf": "0285",
|
||||
"上首造字/No.63-上首迎风手写体.ttf": "0286",
|
||||
"上首造字/No.64-上首奕星体.ttf": "0287",
|
||||
"上首造字/No.65-上首山河体.ttf": "0288",
|
||||
"上首造字/No.66-上首和风体.ttf": "0289",
|
||||
"上首造字/No.67-上首轩宋体.ttf": "0290",
|
||||
"上首造字/No.68-上首正雅体.ttf": "0291",
|
||||
"上首造字/No.69-上首太空体.ttf": "0292",
|
||||
"上首造字/No.7-上首文正体.ttf": "0293",
|
||||
"上首造字/No.70-上首夏木体.ttf": "0294",
|
||||
"上首造字/No.71-上首锐锋体.TTF": "0295",
|
||||
"上首造字/No.72-上首喵尾体.ttf": "0296",
|
||||
"上首造字/No.73-上首粉笔体.ttf": "0297",
|
||||
"上首造字/No.74-上首战戟体.ttf": "0298",
|
||||
"上首造字/No.75-上首玉立体.ttf": "0299",
|
||||
"上首造字/No.76-上首战刃体.ttf": "0300",
|
||||
"上首造字/No.77-上首苍穹书法体.ttf": "0301",
|
||||
"上首造字/No.78-上首梦黑体.ttf": "0302",
|
||||
"上首造字/No.79-上首博瀚体.ttf": "0303",
|
||||
"上首造字/No.8-上首京东体.ttf": "0304",
|
||||
"上首造字/No.80-上首乐高体.ttf": "0305",
|
||||
"上首造字/No.81-上首胖墩体.ttf": "0306",
|
||||
"上首造字/No.82-上首简黑粗体.ttf": "0307",
|
||||
"上首造字/No.83-上首粗楷体.ttf": "0308",
|
||||
"上首造字/No.84-上首状元体.ttf": "0309",
|
||||
"上首造字/No.85-上首元气体.ttf": "0310",
|
||||
"上首造字/No.86-上首圆盾体.ttf": "0311",
|
||||
"上首造字/No.87-上首乾坤体.ttf": "0312",
|
||||
"上首造字/No.88-上首典宋体.ttf": "0313",
|
||||
"上首造字/No.89-上首金刚体.ttf": "0314",
|
||||
"上首造字/No.9-上首宽云体.ttf": "0315",
|
||||
"上首造字/No.90-上首嘻哈体.ttf": "0316",
|
||||
"上首造字/No.91-上首婷雅体.ttf": "0317",
|
||||
"上首造字/No.92-上首虎啸体.ttf": "0318",
|
||||
"上首造字/No.93-上首萌动体.ttf": "0319",
|
||||
"上首造字/No.94-上首奥丁体.ttf": "0320",
|
||||
"上首造字/No.95-上首昆仑体.ttf": "0321",
|
||||
"上首造字/No.96-上首锦宋体.ttf": "0322",
|
||||
"上首造字/No.97-上首国宋体.ttf": "0323",
|
||||
"上首造字/No.98-上首趣泡手写体.ttf": "0324",
|
||||
"上首造字/No.99-上首元正体.ttf": "0325",
|
||||
"上首造字/Sounso Art.ttf": "0326",
|
||||
"上首造字/Sounso Beauty.ttf": "0327",
|
||||
"上首造字/Sounso Cecily.ttf": "0328",
|
||||
"上首造字/Sounso Diamond.ttf": "0329",
|
||||
"上首造字/Sounso Earnestly.ttf": "0330",
|
||||
"上首造字/上首兰亭体.ttf": "0331",
|
||||
"上首造字/上首凤凰体.ttf": "0332",
|
||||
"上首造字/上首刀锋体.ttf": "0333",
|
||||
"上首造字/上首华光体.ttf": "0334",
|
||||
"上首造字/上首华木体.ttf": "0335",
|
||||
"上首造字/上首南城体.ttf": "0336",
|
||||
"上首造字/上首品尚体.ttf": "0337",
|
||||
"上首造字/上首战马体.ttf": "0338",
|
||||
"上首造字/上首星语体.ttf": "0339",
|
||||
"上首造字/上首熔岩体.ttf": "0340",
|
||||
"上首造字/上首纤云体.ttf": "0341",
|
||||
"上首造字/上首纯元体.ttf": "0342",
|
||||
"上首造字/上首苍兰体.ttf": "0343",
|
||||
"上首造字/上首轩辕体.ttf": "0344",
|
||||
"上首造字/上首锦云体.ttf": "0345",
|
||||
"上首造字/上首雅居体.ttf": "0346",
|
||||
"其他字体/AlimamaDaoLiTi.ttf": "0347",
|
||||
"其他字体/Hangeuljaemin4-Regular.ttf": "0348",
|
||||
"其他字体/I.顏體.ttf": "0349",
|
||||
"其他字体/XCDUANZHUANGSONGTI.ttf": "0350",
|
||||
"其他字体/qiji-combo.ttf": "0351",
|
||||
"其他字体/临海隶书.ttf": "0352",
|
||||
"其他字体/京華老宋体_KingHwa_OldSong.ttf": "0353",
|
||||
"其他字体/优设标题黑.ttf": "0354",
|
||||
"其他字体/包图小白体.ttf": "0355",
|
||||
"其他字体/源界明朝.ttf": "0356",
|
||||
"其他字体/演示佛系体.ttf": "0357",
|
||||
"其他字体/站酷快乐体.ttf": "0358",
|
||||
"其他字体/问藏书房.ttf": "0359",
|
||||
"其他字体/霞鹜臻楷.ttf": "0360",
|
||||
"庞门正道-测试/庞门正道标题体.ttf": "0016",
|
||||
"庞门正道/庞门正道标题体.ttf": "0361",
|
||||
"王漢宗/王漢宗勘亭流繁.ttf": "0362",
|
||||
"王漢宗/王漢宗新潮體.ttf": "0363",
|
||||
"王漢宗/王漢宗波卡體空陰.ttf": "0364",
|
||||
"王漢宗/王漢宗細黑體繁.ttf": "0365",
|
||||
"王漢宗/王漢宗綜藝體雙空陰.ttf": "0366",
|
||||
"王漢宗/王漢宗超明體繁.ttf": "0367",
|
||||
"王漢宗/王漢宗酷儷海報.ttf": "0368",
|
||||
"王漢宗/王漢宗顏楷體繁.ttf": "0369"
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,176 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
生成字体清单文件
|
||||
生成字体清单文件(稳定 ID 版本)
|
||||
扫描 fonts/ 目录下的所有字体文件,同时生成:
|
||||
1. frontend/public/fonts.json
|
||||
2. miniprogram/assets/fonts.json
|
||||
3. miniprogram/assets/fonts.js
|
||||
|
||||
ID 分配规则:
|
||||
1. 已存在字体(按 relativePath 识别)保持原 ID 不变。
|
||||
2. 新增字体按“上次游标”分配新 ID。
|
||||
3. ID 从 0001 递增到 10000,之后循环分配(跳过当前正在使用的 ID)。
|
||||
"""
|
||||
|
||||
import os
|
||||
import json
|
||||
from pathlib import Path
|
||||
from urllib.parse import unquote, urlparse
|
||||
|
||||
FONT_DIR = Path('fonts')
|
||||
WEB_FONTS_JSON = Path('frontend/public/fonts.json')
|
||||
MP_FONTS_JSON = Path('miniprogram/assets/fonts.json')
|
||||
MP_FONTS_JS = Path('miniprogram/assets/fonts.js')
|
||||
ID_STATE_FILE = Path('scripts/font-id-state.json')
|
||||
|
||||
ID_MIN = 1
|
||||
ID_MAX = 10000
|
||||
|
||||
|
||||
def format_font_id(num):
|
||||
return str(num).zfill(4)
|
||||
|
||||
|
||||
def parse_font_id(raw):
|
||||
try:
|
||||
value = int(str(raw).strip())
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
if ID_MIN <= value <= ID_MAX:
|
||||
return value
|
||||
return None
|
||||
|
||||
|
||||
def increment_id(num):
|
||||
return ID_MIN if num >= ID_MAX else num + 1
|
||||
|
||||
|
||||
def normalize_relative_path(raw_path):
|
||||
if not raw_path:
|
||||
return None
|
||||
|
||||
text = str(raw_path).strip()
|
||||
if not text:
|
||||
return None
|
||||
|
||||
parsed = urlparse(text)
|
||||
if parsed.scheme and parsed.netloc:
|
||||
text = parsed.path
|
||||
|
||||
text = unquote(text)
|
||||
text = text.split('?', 1)[0].split('#', 1)[0]
|
||||
text = text.replace('\\', '/')
|
||||
|
||||
if '/fonts/' in text:
|
||||
text = text.split('/fonts/', 1)[1]
|
||||
elif text.startswith('fonts/'):
|
||||
text = text[len('fonts/'):]
|
||||
elif text.startswith('/fonts'):
|
||||
text = text[len('/fonts'):]
|
||||
|
||||
text = text.lstrip('/')
|
||||
return text or None
|
||||
|
||||
|
||||
def load_manifest_id_map(manifest_file):
|
||||
mapping = {}
|
||||
if not manifest_file.exists():
|
||||
return mapping
|
||||
|
||||
try:
|
||||
with open(manifest_file, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
except (OSError, json.JSONDecodeError):
|
||||
return mapping
|
||||
|
||||
if not isinstance(data, list):
|
||||
return mapping
|
||||
|
||||
for item in data:
|
||||
if not isinstance(item, dict):
|
||||
continue
|
||||
relative_path = normalize_relative_path(
|
||||
item.get('path') or item.get('relativePath')
|
||||
)
|
||||
id_num = parse_font_id(item.get('id'))
|
||||
if relative_path and id_num:
|
||||
mapping[relative_path] = format_font_id(id_num)
|
||||
|
||||
return mapping
|
||||
|
||||
|
||||
def load_id_state(state_file):
|
||||
default_state = {
|
||||
'version': 1,
|
||||
'nextId': ID_MIN,
|
||||
'pathToId': {},
|
||||
}
|
||||
|
||||
if not state_file.exists():
|
||||
return default_state
|
||||
|
||||
try:
|
||||
with open(state_file, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
except (OSError, json.JSONDecodeError):
|
||||
return default_state
|
||||
|
||||
if not isinstance(data, dict):
|
||||
return default_state
|
||||
|
||||
path_to_id = {}
|
||||
raw_map = data.get('pathToId')
|
||||
if isinstance(raw_map, dict):
|
||||
for path_key, raw_id in raw_map.items():
|
||||
relative_path = normalize_relative_path(path_key)
|
||||
id_num = parse_font_id(raw_id)
|
||||
if relative_path and id_num:
|
||||
path_to_id[relative_path] = format_font_id(id_num)
|
||||
|
||||
next_id = parse_font_id(data.get('nextId')) or ID_MIN
|
||||
|
||||
return {
|
||||
'version': 1,
|
||||
'nextId': next_id,
|
||||
'pathToId': path_to_id,
|
||||
}
|
||||
|
||||
|
||||
def save_id_state(state, state_file):
|
||||
state_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
normalized_map = dict(sorted(state['pathToId'].items(), key=lambda x: x[0]))
|
||||
data = {
|
||||
'version': 1,
|
||||
'nextId': state['nextId'],
|
||||
'pathToId': normalized_map,
|
||||
}
|
||||
with open(state_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(data, f, ensure_ascii=False, indent=2)
|
||||
f.write('\n')
|
||||
|
||||
|
||||
def bootstrap_state_mappings(state):
|
||||
# 优先级:state 文件 > 小程序现有清单 > web 现有清单
|
||||
for manifest_path in (MP_FONTS_JSON, WEB_FONTS_JSON):
|
||||
mapping = load_manifest_id_map(manifest_path)
|
||||
for relative_path, font_id in mapping.items():
|
||||
state['pathToId'].setdefault(relative_path, font_id)
|
||||
|
||||
if parse_font_id(state.get('nextId')) is None:
|
||||
state['nextId'] = ID_MIN
|
||||
|
||||
if state['nextId'] == ID_MIN and state['pathToId']:
|
||||
max_id = max(parse_font_id(v) for v in state['pathToId'].values())
|
||||
state['nextId'] = increment_id(max_id)
|
||||
|
||||
|
||||
def allocate_new_id(start_id, used_ids):
|
||||
candidate = start_id
|
||||
for _ in range(ID_MAX):
|
||||
if candidate not in used_ids:
|
||||
return candidate, increment_id(candidate)
|
||||
candidate = increment_id(candidate)
|
||||
raise RuntimeError('可用 ID 已耗尽(0001-10000 全部被当前字体占用)')
|
||||
|
||||
def scan_fonts(font_dir='fonts'):
|
||||
"""扫描字体目录,返回字体信息列表"""
|
||||
@@ -45,14 +206,48 @@ def scan_fonts(font_dir='fonts'):
|
||||
|
||||
fonts.append(font_info)
|
||||
|
||||
# 统一排序后分配 4 位数字 id(0001、0002...)
|
||||
fonts = sorted(fonts, key=lambda x: (x['category'], x['name'], x['filename']))
|
||||
for index, font in enumerate(fonts, start=1):
|
||||
font['id'] = f"{index:04d}"
|
||||
|
||||
# 固定顺序,保证分配冲突时结果稳定
|
||||
fonts = sorted(fonts, key=lambda x: (x['category'], x['name'], x['filename'], x['relativePath']))
|
||||
return fonts
|
||||
|
||||
|
||||
def assign_stable_ids(fonts):
|
||||
state = load_id_state(ID_STATE_FILE)
|
||||
bootstrap_state_mappings(state)
|
||||
|
||||
cursor = parse_font_id(state.get('nextId')) or ID_MIN
|
||||
used_ids = set()
|
||||
new_count = 0
|
||||
|
||||
for font in fonts:
|
||||
relative_path = font['relativePath']
|
||||
existing_id = state['pathToId'].get(relative_path)
|
||||
existing_num = parse_font_id(existing_id)
|
||||
|
||||
if existing_num and existing_num not in used_ids:
|
||||
assigned_num = existing_num
|
||||
else:
|
||||
if existing_num and existing_num in used_ids:
|
||||
print(
|
||||
f"警告: 发现 ID 冲突,路径 {relative_path} 原 ID {existing_id} 将重新分配。"
|
||||
)
|
||||
assigned_num, cursor = allocate_new_id(cursor, used_ids)
|
||||
state['pathToId'][relative_path] = format_font_id(assigned_num)
|
||||
new_count += 1
|
||||
|
||||
used_ids.add(assigned_num)
|
||||
font['id'] = format_font_id(assigned_num)
|
||||
|
||||
state['nextId'] = cursor
|
||||
save_id_state(state, ID_STATE_FILE)
|
||||
|
||||
return {
|
||||
'newCount': new_count,
|
||||
'nextId': format_font_id(cursor),
|
||||
'stateFile': str(ID_STATE_FILE),
|
||||
}
|
||||
|
||||
|
||||
def build_manifest(fonts, path_prefix):
|
||||
"""根据路径前缀构建对外清单"""
|
||||
prefix = f"/{str(path_prefix or '').strip('/')}"
|
||||
@@ -91,18 +286,25 @@ def write_fonts_js(fonts, output_file):
|
||||
def main():
|
||||
"""主函数"""
|
||||
# 扫描字体(唯一来源:仓库根目录 fonts/)
|
||||
fonts = scan_fonts('fonts')
|
||||
fonts = scan_fonts(str(FONT_DIR))
|
||||
|
||||
print(f"找到 {len(fonts)} 个字体文件")
|
||||
|
||||
allocation_result = assign_stable_ids(fonts)
|
||||
print(
|
||||
f"ID 分配完成:新增 {allocation_result['newCount']} 个,"
|
||||
f"下次起始 ID {allocation_result['nextId']},"
|
||||
f"状态文件 {allocation_result['stateFile']}"
|
||||
)
|
||||
|
||||
# Web 清单:统一指向根目录 fonts
|
||||
web_fonts = build_manifest(fonts, '/fonts')
|
||||
write_fonts_json(web_fonts, 'frontend/public/fonts.json')
|
||||
write_fonts_json(web_fonts, str(WEB_FONTS_JSON))
|
||||
|
||||
# 小程序清单:同样指向根目录 fonts(与 web 共用一份字体目录)
|
||||
miniprogram_fonts = build_manifest(fonts, '/fonts')
|
||||
write_fonts_json(miniprogram_fonts, 'miniprogram/assets/fonts.json')
|
||||
write_fonts_js(miniprogram_fonts, 'miniprogram/assets/fonts.js')
|
||||
write_fonts_json(miniprogram_fonts, str(MP_FONTS_JSON))
|
||||
write_fonts_js(miniprogram_fonts, str(MP_FONTS_JS))
|
||||
|
||||
# 统计信息
|
||||
categories = {}
|
||||
|
||||
Reference in New Issue
Block a user