有风塘主
发布于 2024-10-26 / 26 阅读
0
0

使用NodeJS批量提取字体图标的svg

使用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')

评论