UNPKG

font-carrier-ts

Version:

字体搬运工,中文字体解决方案,iconfont

313 lines (254 loc) 8.15 kB
var path = require('path') var fs = require('fs'); var _ = require('lodash') var helper = require('./helper.js') var opentype = require('opentype.js') var DOMParser = require('xmldom').DOMParser var svg2ttf = require('svg2ttf') var ttf2svg = require('ttf2svg') var ttf2eot = require('ttf2eot') var ttf2woff = require('ttf2woff') var fontEngine = { svg2svg: function(input) { if (Buffer.isBuffer(input)) return input return new Buffer(input) }, svg2ttf: function(input, options) { if (Buffer.isBuffer(input)) input = input.toString() return new Buffer(svg2ttf(input, options).buffer) }, svg2eot: function(input, options) { var ttfBuffer = this.svg2ttf(input, options) return this.ttf2eot(ttfBuffer); }, svg2woff: function(input, options) { var ttfBuffer = this.svg2ttf(input, options) return this.ttf2woff(ttfBuffer); }, ttf2ttf: function(input) { if (Buffer.isBuffer(input)) return input return new Buffer(input) }, ttf2svg: function(input) { //console.log(ttf2svg(input)) return new Buffer(ttf2svg(input)) }, ttf2eot: function(input) { return new Buffer(ttf2eot(input).buffer) }, ttf2woff: function(input) { return new Buffer(ttf2woff(input).buffer) } } var ALL_FONTS_TYPES = ['svg', 'ttf', 'eot', 'woff'] var _normalizeInput = function(input) { if (!input) return false //a buffer if (Buffer.isBuffer(input)) return input //a path if (_.isString(input) && fs.existsSync(input)) { return fs.readFileSync(input) } //a svg font string if (_.isString(input) && /font-face/.test(input)) { return new Buffer(input) } return false } /** * 解析一个字体转换成js对象 * @param {[type]} input [description] * @return {[type]} [description] */ fontEngine.parse = (function() { //参考 svg2ttf里面的解析代码 //https://github.com/fontello/svg2ttf var _getGlyph = function(glyphElem) { var glyph = {}; glyph.d = glyphElem.getAttribute('d').trim() glyph.unicode = helper.normalizeUnicode(glyphElem.getAttribute('unicode')) glyph.name = glyphElem.getAttribute('glyph-name') if (glyphElem.getAttribute('horiz-adv-x')) { glyph.horizAdvX = parseInt(glyphElem.getAttribute('horiz-adv-x'), 10) } return glyph; } var _parseTtfFont = function(ttfBuffer) { function toArrayBuffer(buffer) { var arrayBuffer = new ArrayBuffer(buffer.length) var data = new Uint8Array(arrayBuffer) for (var i = 0; i < buffer.length; i += 1) { data[i] = buffer[i] } return arrayBuffer } var font = opentype.parse(toArrayBuffer(ttfBuffer)) if (!font.supported) { return helper.showError('Font is not supported (is this a Postscript font?)'); } var hhea = font.tables.hhea var head = font.tables.head var name = font.tables.name var fontObjs = { options: { id: name.postScriptName || 'iconfont', horizAdvX: hhea.advanceWidthMax || 1024, vertAdvY: head.unitsPerEm || 1024 }, fontface: { fontFamily: name.fontFamily || 'iconfont', ascent: hhea.ascender, descent: hhea.descender, unitsPerEm: head.unitsPerEm }, glyphs: {} } var path, unicode _.each(font.glyphs, function(g) { try { path = g.path.toPathData() if (path && _.isArray(g.unicodes)) { _.each(g.unicodes,function(_unicode){ unicode = '&#x' + (_unicode).toString(16) + ';' fontObjs.glyphs[unicode] = { d: path, unicode: unicode, name: g.name || 'uni' + _unicode, horizAdvX: g.advanceWidth, vertAdvY: fontObjs.options.vertAdvY } }) } } catch (e) { //todo debug options //helper.showError(e) } }) return fontObjs } var _parseSvgFont = function(svgBuffer) { var svgStr = svgBuffer.toString() var doc = (new DOMParser()).parseFromString(svgStr, 'application/xml') var fontElem = doc.getElementsByTagName('font')[0] var fontFaceElem = fontElem.getElementsByTagName('font-face')[0] var font = { options: { id: fontElem.getAttribute('id') || 'iconfont' }, fontface: { fontFamily: fontFaceElem.getAttribute('font-family') || 'iconfont', fontStretch: fontFaceElem.getAttribute('font-stretch') || 'normal' }, glyphs: {} } // Get <font-face> numeric attributes attrs = { ascent: 'ascent', descent: 'descent', unitsPerEm: 'units-per-em', fontWeight: 'font-weight' } _.forEach(attrs, function(val, key) { if (fontFaceElem.hasAttribute(val)) { font.fontface[key] = parseInt(fontFaceElem.getAttribute(val), 10) } }) var fontfaceHeight = font.fontface.unitsPerEm var attrs = { horizAdvX: 'horiz-adv-x', vertAdvY: 'vert-adv-y' // horizOriginX: 'horiz-origin-x', // horizOriginY: 'horiz-origin-y', // vertOriginX: 'vert-origin-x', // vertOriginY: 'vert-origin-y' } _.forEach(attrs, function(val, key) { if (fontElem.hasAttribute(val)) { font.options[key] = parseInt(fontElem.getAttribute(val), 10) } }) if (!font.options.vertAdvY) { font.options.vertAdvY = fontfaceHeight } if (!font.options.horizAdvX) { font.options.horizAdvX = fontfaceHeight } _.forEach(fontElem.getElementsByTagName('glyph'), function(glyphElem) { var glyph = _getGlyph(glyphElem) font.glyphs[glyph.unicode] = glyph if (!glyph.horizAdvX && font.options.horizAdvX) { glyph.horizAdvX = font.options.horizAdvX } if (!glyph.vertAdvY) { glyph.vertAdvY = font.options.vertAdvY ? font.options.vertAdvY : fontfaceHeight } }) return font } var parse = function(input) { var inputBuffer = _normalizeInput(input) if (!inputBuffer) { helper.showError('font convert input error,support path,buffer,string!') return } if (/<svg/.test(inputBuffer.toString())) return _parseSvgFont(inputBuffer) //不是svg字体就默认是ttf字体,就使用ttf.js进行解析 return _parseTtfFont(inputBuffer) } return parse })() /** * 一次性的生成其余几种字体,接受一个svg字体 * * @param {string|buffer|path} input 字体输入可以是路径,buffer对象,string对象 * @param {string} outputTypes 字体输出的类型,默认是所有四种 * @param {string} outputPath 字体的输出路径,不需要带后缀 * @return {array} outFonts 返回转换后的字体buffer数组 */ fontEngine.convert = (function() { var _normalizePath = function(p) { if (!p) return false if (path.extname(p)) { p = p.replace(path.extname(p), '') } return p } var _convert = function(svgFontBuffer, outputTypes, options) { var result = {} var preKey = 'svg' var input = svgFontBuffer var ttfBuffer = fontEngine.svg2ttf(input, options) _.each(outputTypes, function(type, k) { if (type === 'svg') { result[type] = input } else { result[type] = fontEngine['ttf2' + type](ttfBuffer, options) } }) return result } var _writeFile = function(output, outFonts) { _.each(outFonts, function(font, type) { fs.writeFileSync(output + '.' + type, font) }) } return function(options) { var inputBuffer = _normalizeInput(options.input) var outputPath = _normalizePath(options.path) var outputTypes = options.types || ALL_FONTS_TYPES if (!inputBuffer) { helper.showError('font convert input error,support path,buffer,string.please check if the file exist,while the input is a path.') return } var outFonts = _convert(inputBuffer, outputTypes, options) if (outputPath) { _writeFile(outputPath, outFonts) } return outFonts } })() /** * 字体转换引擎,提供svg 到ttf,ttf到woff,eot,svg的转换 * 提供字体的解析与转换 */ module.exports = fontEngine