179 lines
9.8 KiB
JavaScript
179 lines
9.8 KiB
JavaScript
// 采集可用字体 → _design-test/font-specimens.json
|
||
// 来源:① 本地素材库 OFL 字体(可商用) ② 本机已安装系统字体(仅预览)
|
||
// 说明:本机 Node / 浏览器均无外网,Google Fonts 无法拉取,故不含 Web 字体。
|
||
// 用法: node _design-test/harvest-fonts.js
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
|
||
const ROOT = path.resolve(__dirname, '..');
|
||
|
||
// ── ① 本地素材库字体(js/data/posters/*.js,全部 OFL-1.1,可商用)──────
|
||
const LOCAL = [
|
||
{ id: 'league-spartan', family: 'League Spartan', cn: 'League Spartan · 几何无衬线', cat: '几何/无衬线', w: '700' },
|
||
{ id: 'fontsource-montserrat', family: 'Montserrat', cn: 'Montserrat · 几何无衬线', cat: '几何/无衬线', w: '800' },
|
||
{ id: 'fontsource-poppins', family: 'Poppins', cn: 'Poppins · 圆几何', cat: '几何/无衬线', w: '700' },
|
||
{ id: 'fontsource-inter', family: 'Inter', cn: 'Inter · 界面无衬线', cat: '几何/无衬线', w: '700' },
|
||
{ id: 'fontsource-space-grotesk', family: 'Space Grotesk', cn: 'Space Grotesk · 科技无衬线', cat: '科技/等宽', w: '700' },
|
||
{ id: 'fontsource-cinzel', family: 'Cinzel', cn: 'Cinzel · 罗马大写碑体', cat: '衬线', w: '700' },
|
||
{ id: 'fontsource-playfair', family: 'Playfair Display', cn: 'Playfair Display · 高对比衬线', cat: '衬线', w: '700' },
|
||
{ id: 'fontsource-lora', family: 'Lora', cn: 'Lora · 书卷衬线', cat: '衬线', w: '700' },
|
||
{ id: 'fontsource-oswald', family: 'Oswald', cn: 'Oswald · 窄体', cat: '窄体/粗黑', w: '500' },
|
||
{ id: 'fontsource-bebas-neue', family: 'Bebas Neue', cn: 'Bebas Neue · 高瘦大写字', cat: '窄体/粗黑', w: '400' },
|
||
{ id: 'fontsource-jetbrains-mono', family: 'JetBrains Mono', cn: 'JetBrains Mono · 等宽', cat: '科技/等宽', w: '700' },
|
||
{ id: 'fontsource-caveat', family: 'Caveat', cn: 'Caveat · 手写', cat: '手写/笔刷', w: '700' }
|
||
];
|
||
|
||
// ── ② 本机已安装字体(浏览器实测存在;仅作预览,商用需自行确认授权)────
|
||
// [字体名, 分类, 一句话特点]
|
||
const SYSTEM = [
|
||
// 几何 / 无衬线
|
||
['Helvetica', '几何/无衬线', '经典瑞士无衬线,Z 的中性标准'],
|
||
['Arial', '几何/无衬线', '最通用的无衬线'],
|
||
['Roboto', '几何/无衬线', 'Google 系统无衬线'],
|
||
['Segoe UI', '几何/无衬线', 'Windows 系统无衬线'],
|
||
['Tahoma', '几何/无衬线', '小字清晰的无衬线'],
|
||
['Verdana', '几何/无衬线', '宽字距、易读'],
|
||
['Trebuchet MS', '几何/无衬线', '带性格的旧金山体'],
|
||
['Calibri', '几何/无衬线', '圆角现代无衬线'],
|
||
['Candara', '几何/无衬线', '优雅的人文无衬线'],
|
||
['Corbel', '几何/无衬线', '开阔的人文无衬线'],
|
||
['Century Gothic', '几何/无衬线', '纯几何圆体'],
|
||
['Gill Sans MT', '几何/无衬线', '英式人文无衬线'],
|
||
['Franklin Gothic Book', '几何/无衬线', '美式哥特体(细)'],
|
||
['Franklin Gothic Medium', '几何/无衬线', '美式哥特体(中)'],
|
||
['Franklin Gothic Demi', '几何/无衬线', '美式哥特体(半粗)'],
|
||
['Microsoft Sans Serif', '几何/无衬线', 'Windows 经典 UI 体'],
|
||
['Tw Cen MT', '几何/无衬线', '二十世纪几何体'],
|
||
['Berlin Sans FB', '几何/无衬线', '有切角性格的展示无衬线'],
|
||
['Bahnschrift', '几何/无衬线', 'DIN 血统可变窄体'],
|
||
['Bahnschrift SemiBold', '几何/无衬线', 'DIN 血统(半粗)'],
|
||
['Arial Narrow', '窄体/粗黑', '压缩无衬线'],
|
||
['Arial Black', '窄体/粗黑', '超重无衬线'],
|
||
['Lucida Sans', '几何/无衬线', '宽圆无衬线'],
|
||
['Lucida Sans Unicode', '几何/无衬线', '宽圆无衬线(大字符集)'],
|
||
['Microsoft YaHei', '几何/无衬线', '微软雅黑(拉丁部分)'],
|
||
// 窄体 / 粗黑 / 展示
|
||
['Impact', '窄体/粗黑', '极致粗窄,Z 一坨重量'],
|
||
['Haettenschweiler', '窄体/粗黑', '超窄粗体'],
|
||
['Britannic Bold', '窄体/粗黑', '英式粗展示体'],
|
||
['Agency FB', '窄体/粗黑', '宽方现代展示体'],
|
||
['Wide Latin', '窄体/粗黑', '超宽衬线大字'],
|
||
['Goudy Stout', '窄体/粗黑', '极重衬线展示体'],
|
||
// 衬线
|
||
['Times New Roman', '衬线', '最经典衬线'],
|
||
['Georgia', '衬线', '屏幕衬线,笔画厚重'],
|
||
['Garamond', '衬线', '法式古典衬线'],
|
||
['Book Antiqua', '衬线', 'Palatino 血统'],
|
||
['Bookman Old Style', '衬线', '厚重书本衬线'],
|
||
['Cambria', '衬线', '屏幕阅读衬线'],
|
||
['Constantia', '衬线', '人文衬线'],
|
||
['Palatino Linotype', '衬线', '人文主义衬线'],
|
||
['Century Schoolbook', '衬线', '教科书衬线'],
|
||
['Century', '衬线', '古典几何衬线'],
|
||
['Calisto MT', '衬线', '过渡期衬线'],
|
||
['Bodoni MT', '衬线', '高对比 Didone,Z 斜画极细'],
|
||
['Elephant', '衬线', '超重衬线'],
|
||
['Engravers MT', '衬线', '刻版罗马大写'],
|
||
['Goudy Old Style', '衬线', '老式衬线'],
|
||
['High Tower Text', '衬线', '古籍感衬线'],
|
||
['Modern No. 20', '衬线', 'Didone 复古'],
|
||
['Perpetua', '衬线', ' Gill 的衬线体'],
|
||
['Perpetua Titling MT', '衬线', '大写标题衬线'],
|
||
['Poor Richard', '衬线', '美式老式衬线'],
|
||
['Castellar', '衬线', '碑体大写(带衬脚)'],
|
||
['Colonna MT', '衬线', '大写碑体'],
|
||
['Imprint MT Shadow', '衬线', '带阴影的碑体'],
|
||
['Niagara Engraved', '衬线', '镂空雕刻体'],
|
||
['Sylfaen', '衬线', '乔治亚衬线'],
|
||
['MS Gothic', '衬线', '日式黑体(拉丁窄)'],
|
||
['Yu Gothic', '几何/无衬线', '日式无衬线'],
|
||
// slab / 方正
|
||
['Rockwell', 'slab/方正', '几何板衬线,Z 方脚'],
|
||
['Rockwell Extra Bold', 'slab/方正', '超重板衬线'],
|
||
['Cooper Black', 'slab/方正', '圆胖粗衬线'],
|
||
// 装饰 / ArtDeco / 趣味
|
||
['Broadway', '装饰/趣味', 'ArtDeco 舞台体'],
|
||
['Showcard Gothic', '装饰/趣味', '手绘招牌体'],
|
||
['Stencil', '装饰/趣味', '模板喷字'],
|
||
['Onyx', '装饰/趣味', '超窄高对比'],
|
||
['Playbill', '装饰/趣味', '西部木牌体'],
|
||
['Algerian', '装饰/趣味', '异域装饰体'],
|
||
['Snap ITC', '装饰/趣味', '弹跳趣味体'],
|
||
['Juice ITC', '装饰/趣味', '手绘卡通体'],
|
||
['Magneto', '装饰/趣味', 'ArtDeco 霓虹体'],
|
||
['Jokerman', '装饰/趣味', '花哨趣味体'],
|
||
['Curlz MT', '装饰/趣味', '卷曲花体'],
|
||
['Chiller', '装饰/趣味', '惊悚手写体'],
|
||
['Pristina', '装饰/趣味', '细笔装饰体'],
|
||
['Harrington', '装饰/趣味', 'ArtDeco 装饰体'],
|
||
['Forte', '装饰/趣味', '笔刷装饰体'],
|
||
['Gigi', '装饰/趣味', '少女感装饰体'],
|
||
['Maiandra GD', '装饰/趣味', '圆角人文展示体'],
|
||
['Tempus Sans ITC', '装饰/趣味', '轻快展示体'],
|
||
['Papyrus', '装饰/趣味', '莎草纸手写体'],
|
||
['Old English Text MT', '装饰/趣味', '哥特黑体'],
|
||
['Viner Hand ITC', '手写/笔刷', '硬笔手写'],
|
||
// 手写 / 笔刷
|
||
['Brush Script MT', '手写/笔刷', '经典笔刷体'],
|
||
['Segoe Script', '手写/笔刷', '系统手写体'],
|
||
['Segoe Print', '手写/笔刷', '系统手写印刷体'],
|
||
['Freestyle Script', '手写/笔刷', '随性笔刷'],
|
||
['French Script MT', '手写/笔刷', '法式连笔'],
|
||
['Edwardian Script ITC', '手写/笔刷', '爱德华花体'],
|
||
['Palace Script MT', '手写/笔刷', '宫廷花体'],
|
||
['Script MT Bold', '手写/笔刷', '粗花体'],
|
||
['Vladimir Script', '手写/笔刷', '自由花体'],
|
||
['Bradley Hand ITC', '手写/笔刷', '手写便签体'],
|
||
['Kristen ITC', '手写/笔刷', '儿童手写体'],
|
||
['Lucida Handwriting', '手写/笔刷', '手写连笔'],
|
||
['Kunstler Script', '手写/笔刷', '德式装饰花体'],
|
||
['Ink Free', '手写/笔刷', '钢笔随手写'],
|
||
['Parchment', '手写/笔刷', '羊皮纸手写'],
|
||
['Vivaldi', '手写/笔刷', '斜体花体'],
|
||
['Comic Sans MS', '手写/笔刷', '手绘马克笔'],
|
||
// 等宽 / 科技
|
||
['Consolas', '科技/等宽', '编程等宽'],
|
||
['Cascadia Code', '科技/等宽', '微软编程等宽'],
|
||
['Cascadia Mono', '科技/等宽', '微软等宽'],
|
||
['Lucida Console', '科技/等宽', '经典等宽'],
|
||
['Courier New', '科技/等宽', '打字机等宽']
|
||
];
|
||
|
||
function pickLocalFile(files, want) {
|
||
const has = (re) => files.find(f => re.test(f));
|
||
return has(new RegExp('-latin-' + want + '-normal\\.woff2$'))
|
||
|| has(/-latin-400-normal\.woff2$/)
|
||
|| has(/-latin-\d+-normal\.woff2$/)
|
||
|| has(/-latin-.*normal\.woff2$/)
|
||
|| files.find(function (x) { return /\.woff2$/.test(x); }) || files[0];
|
||
}
|
||
|
||
const out = [];
|
||
let missing = 0;
|
||
for (const f of LOCAL) {
|
||
const p = path.join(ROOT, 'js', 'data', 'posters', f.id + '.js');
|
||
if (!fs.existsSync(p)) { console.log(' ✗ 缺源文件', f.id); missing++; continue; }
|
||
const t = fs.readFileSync(p, 'utf8');
|
||
const files = [...t.matchAll(/"file":"posters\/[^"]+\/([^"]+\.(?:woff2|woff|ttf|otf))"/g)].map(m => m[1]);
|
||
const latin = files.filter(x => /-latin-/.test(x));
|
||
const pick = pickLocalFile(latin.length ? latin : files, f.w);
|
||
if (!pick) { console.log(' ✗ 无 woff2', f.id); missing++; continue; }
|
||
out.push({
|
||
slug: f.id, family: f.family, cn: f.cn, cat: f.cat, weight: f.w,
|
||
kind: 'ofl', license: 'OFL-1.1 · 可商用',
|
||
fmt: (pick.split('.').pop() || 'woff2').toLowerCase(),
|
||
src: '../js/data/posters/' + f.id + '/files/' + pick
|
||
});
|
||
console.log(' ✓', f.family, '->', pick);
|
||
}
|
||
for (const [family, cat, cn] of SYSTEM) {
|
||
out.push({ slug: 'sys-' + family.toLowerCase().replace(/[^a-z0-9]+/g, '-'), family, cn, cat, weight: '', kind: 'system', license: '系统字体 · 商用需自行授权', src: '' });
|
||
}
|
||
console.log('本地 OFL 字体:', LOCAL.length - missing, '| 系统字体:', SYSTEM.length);
|
||
|
||
const cats = {};
|
||
out.forEach(f => { cats[f.cat] = (cats[f.cat] || 0) + 1; });
|
||
fs.writeFileSync(path.join(__dirname, 'font-specimens.json'),
|
||
JSON.stringify({ total: out.length, cats, fonts: out }, null, 0));
|
||
console.log('合计', out.length, '款 ·', JSON.stringify(cats));
|