使用NodeJS批量提取字体图标的svg
需求
从图标字体文件(ttf格式)中,批量将每个图标提取为单独的svg图片
代码
const computeBoundingBox = require('fonteditor-core/lib/graphics/computeBoundingBox')
const pathAdjust = require('fonteditor-core/lib/graphics/pathAdjust').default
const pathCeil = require('fonteditor-core/lib/graphics/pathCeil').default
const contours2svg = require('fonteditor-core/lib/ttf/util/contours2svg').default
const glyf2svgPath = (glyf, opt = {}) => {
opt = {
...(opt || []),
size: 128,
unitsPerEm: 1024
}
let g = {
size: opt.size || 128,
unitsPerEm: opt.unitsPerEm,
name: glyf.name,
fillColor: opt.fillColor || '#000'
};
if (glyf.contours && glyf.contours.length) {
let contours = JSON.parse(JSON.stringify(glyf.contours));
let bound = computeBoundingBox.computePath.apply(null, contours);
let originSize = Math.max(bound.width, bound.height);
let scale = opt.unitsPerEm / originSize;
contours.forEach(function (contour) {
pathAdjust(contour, 1, 1, -bound.x, -bound.y - bound.height / 2);
pathAdjust(contour, 1, -1, 0, 0);
pathAdjust(contour, scale, scale, (originSize - bound.width) / 2, bound.height / 2);
pathCeil(contour, 2);
});
g.d = contours2svg(contours);
}
return g.d;
}
module.exports.default = glyf2svgPath
#!/usr/bin/env node
var FonteditorCore = require('fonteditor-core');
var contours2svg = require('fonteditor-core/lib/ttf/util/contours2svg').default
var path = require('path')
var fs = require('fs')
var glyf2svgPath = require('./glyf2svgPath').default
const string = require('fonteditor-core/lib/common/string').default
var Font = FonteditorCore.Font
var config = {
inputTtf: path.resolve(process.cwd(), './data/input.ttf'),
outputDir: path.resolve(process.cwd(), './output')
}
const buffer = fs.readFileSync(config.inputTtf);
// read font data, support ArrayBuffer | Buffer | string
const font = Font.create(buffer, {
// support ttf, woff, woff2, eot, otf, svg
type: 'ttf',
// only read `a`, `b` glyphs
// subset: [65, 66],
// save font hinting
hinting: false,
// transform ttf compound glyph to simple
compound2simple: false,
// inflate function for woff
inflate: null,
// for svg path
combinePath: false,
});
const fontGlyfList = font.get().glyf || []
const fontListMap = new Map()
fontGlyfList.forEach(glyf => {
if (!glyf || !glyf.name) {
return
}
const name = glyf.name.toLowerCase()
// 10进制
const unicode = glyf.unicode[0].toString(16)
fontListMap.set(name, {
name,
unicode,
svgPath: glyf2svgPath(glyf)
})
})
// 排序+重新编码
const nameList = [...fontListMap.keys()].sort()
let startUnicode = 600
const fontList = nameList.map((name, i) => {
return {
...fontListMap.get(name),
unicode: 'e' + (startUnicode + i)
}
})
// 输出为svg文件
const SVG_XML_TPL = '<?xml version="1.0" encoding="utf-8"?>\n' +
'<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n' +
'<svg id="${name}" unicode="${unicode}" width="128" height="128" style="width:128px;height:128px;" version="1.1"\n' +
' xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" enable-background="new 0 0 1024 1024"\n' +
' xml:space="preserve">\n' +
' <path fill="#666" d="${svgPath}"/>\n' +
'</svg>'
const svgList = fontList.map(font => {
return {
fileName: `${font.name}.svg`,
content: string.format(SVG_XML_TPL, font)
}
})
// 输出文件
for (let svgFile of svgList) {
fs.writeFileSync(path.resolve(config.outputDir, svgFile.fileName), svgFile.content)
}
console.log('finish')