Files

179 lines
9.8 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 采集可用字体 → _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));