fonteditor-core
Version:
fonts (ttf, woff, woff2, eot, svg, otf) parse, write, transform, glyph adjust.
266 lines (251 loc) • 8.58 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = ttf2woff;
var _reader = _interopRequireDefault(require("./reader"));
var _writer = _interopRequireDefault(require("./writer"));
var _string = _interopRequireDefault(require("../common/string"));
var _string2 = _interopRequireDefault(require("./util/string"));
var _error = _interopRequireDefault(require("./error"));
var _default = _interopRequireDefault(require("./data/default"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file ttf转换为woff
* @author mengke01(kekee000@gmail.com)
*
* woff format:
* http://www.w3.org/TR/2012/REC-WOFF-20121213/
*
* references:
* https://github.com/fontello/ttf2woff
* https://github.com/nodeca/pako
*/
/* eslint-disable no-multi-spaces */
/**
* metadata 转换成XML
*
* @param {Object} metadata metadata
*
* @example
* metadata json:
*
* {
* "uniqueid": "",
* "vendor": {
* "name": "",
* "url": ""
* },
* "credit": [
* {
* "name": "",
* "url": "",
* "role": ""
* }
* ],
* "description": "",
* "license": {
* "id": "",
* "url": "",
* "text": ""
* },
* "copyright": "",
* "trademark": "",
* "licensee": ""
* }
*
* @return {string} xml字符串
*/
function metadata2xml(metadata) {
var xml = '' + '<?xml version="1.0" encoding="UTF-8"?>' + '<metadata version="1.0">';
metadata.uniqueid = metadata.uniqueid || _default.default.fontId + '.' + Date.now();
xml += '<uniqueid id="' + _string.default.encodeHTML(metadata.uniqueid) + '" />';
if (metadata.vendor) {
xml += '<vendor name="' + _string.default.encodeHTML(metadata.vendor.name) + '"' + ' url="' + _string.default.encodeHTML(metadata.vendor.url) + '" />';
}
if (metadata.credit) {
xml += '<credits>';
var credits = metadata.credit instanceof Array ? metadata.credit : [metadata.credit];
credits.forEach(function (credit) {
xml += '<credit name="' + _string.default.encodeHTML(credit.name) + '"' + ' url="' + _string.default.encodeHTML(credit.url) + '"' + ' role="' + _string.default.encodeHTML(credit.role || 'Contributor') + '" />';
});
xml += '</credits>';
}
if (metadata.description) {
xml += '<description><text xml:lang="en">' + _string.default.encodeHTML(metadata.description) + '</text></description>';
}
if (metadata.license) {
xml += '<license url="' + _string.default.encodeHTML(metadata.license.url) + '"' + ' id="' + _string.default.encodeHTML(metadata.license.id) + '"><text xml:lang="en">';
xml += _string.default.encodeHTML(metadata.license.text);
xml += '</text></license>';
}
if (metadata.copyright) {
xml += '<copyright><text xml:lang="en">';
xml += _string.default.encodeHTML(metadata.copyright);
xml += '</text></copyright>';
}
if (metadata.trademark) {
xml += '<trademark><text xml:lang="en">' + _string.default.encodeHTML(metadata.trademark) + '</text></trademark>';
}
if (metadata.licensee) {
xml += '<licensee name="' + _string.default.encodeHTML(metadata.licensee) + '"/>';
}
xml += '</metadata>';
return xml;
}
/**
* ttf格式转换成woff字体格式
*
* @param {ArrayBuffer} ttfBuffer ttf缓冲数组
* @param {Object} options 选项
* @param {Object} options.metadata 字体相关的信息
* @param {Object} options.deflate 压缩相关函数
*
* @return {ArrayBuffer} woff格式byte流
*/
function ttf2woff(ttfBuffer) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
// woff 头部结构
var woffHeader = {
signature: 0x774F4646,
// for woff
flavor: 0x10000,
// for ttf
length: 0,
numTables: 0,
reserved: 0,
totalSfntSize: 0,
majorVersion: 0,
minorVersion: 0,
metaOffset: 0,
metaLength: 0,
metaOrigLength: 0,
privOffset: 0,
privLength: 0
};
var ttfReader = new _reader.default(ttfBuffer);
var tableEntries = [];
var numTables = ttfReader.readUint16(4); // 读取ttf表个数
var tableEntry;
var deflatedData;
var i;
var l;
if (numTables <= 0 || numTables > 100) {
_error.default.raise(10101);
}
// 读取ttf表索引信息
ttfReader.seek(12);
for (i = 0; i < numTables; ++i) {
tableEntry = {
tag: ttfReader.readString(ttfReader.offset, 4),
checkSum: ttfReader.readUint32(),
offset: ttfReader.readUint32(),
length: ttfReader.readUint32()
};
var entryOffset = ttfReader.offset;
if (tableEntry.tag === 'head') {
// 读取font revision
woffHeader.majorVersion = ttfReader.readUint16(tableEntry.offset + 4);
woffHeader.minorVersion = ttfReader.readUint16(tableEntry.offset + 6);
}
// ttf 表数据
var sfntData = ttfReader.readBytes(tableEntry.offset, tableEntry.length);
// 对数据进行压缩
if (options.deflate) {
deflatedData = options.deflate(sfntData);
// 这里需要判断是否压缩后数据小于原始数据
if (deflatedData.length < sfntData.length) {
tableEntry.data = deflatedData;
tableEntry.deflated = true;
} else {
tableEntry.data = sfntData;
}
} else {
tableEntry.data = sfntData;
}
tableEntry.compLength = tableEntry.data.length;
tableEntries.push(tableEntry);
ttfReader.seek(entryOffset);
}
if (!tableEntries.length) {
_error.default.raise(10204);
}
// 对table进行排序
tableEntries = tableEntries.sort(function (a, b) {
return a.tag === b.tag ? 0 : a.tag < b.tag ? -1 : 1;
});
// 计算offset和 woff size
var woffSize = 44 + 20 * numTables; // header size + table entries
var ttfSize = 12 + 16 * numTables;
for (i = 0, l = tableEntries.length; i < l; ++i) {
tableEntry = tableEntries[i];
tableEntry.offset = woffSize;
// 4字节对齐
woffSize += tableEntry.compLength + (tableEntry.compLength % 4 ? 4 - tableEntry.compLength % 4 : 0);
ttfSize += tableEntry.length + (tableEntry.length % 4 ? 4 - tableEntry.length % 4 : 0);
}
// 计算metaData
var metadata = null;
if (options.metadata) {
var xml = _string2.default.toUTF8Bytes(metadata2xml(options.metadata));
if (options.deflate) {
deflatedData = options.deflate(xml);
if (deflatedData.length < xml.length) {
metadata = deflatedData;
} else {
metadata = xml;
}
} else {
metadata = xml;
}
woffHeader.metaLength = metadata.length;
woffHeader.metaOrigLength = xml.length;
woffHeader.metaOffset = woffSize;
// metadata header + length
woffSize += woffHeader.metaLength + (woffHeader.metaLength % 4 ? 4 - woffHeader.metaLength % 4 : 0);
}
woffHeader.numTables = tableEntries.length;
woffHeader.length = woffSize;
woffHeader.totalSfntSize = ttfSize;
// 写woff数据
var woffWriter = new _writer.default(new ArrayBuffer(woffSize));
// 写woff头部
woffWriter.writeUint32(woffHeader.signature);
woffWriter.writeUint32(woffHeader.flavor);
woffWriter.writeUint32(woffHeader.length);
woffWriter.writeUint16(woffHeader.numTables);
woffWriter.writeUint16(woffHeader.reserved);
woffWriter.writeUint32(woffHeader.totalSfntSize);
woffWriter.writeUint16(woffHeader.majorVersion);
woffWriter.writeUint16(woffHeader.minorVersion);
woffWriter.writeUint32(woffHeader.metaOffset);
woffWriter.writeUint32(woffHeader.metaLength);
woffWriter.writeUint32(woffHeader.metaOrigLength);
woffWriter.writeUint32(woffHeader.privOffset);
woffWriter.writeUint32(woffHeader.privLength);
// 写woff表索引
for (i = 0, l = tableEntries.length; i < l; ++i) {
tableEntry = tableEntries[i];
woffWriter.writeString(tableEntry.tag);
woffWriter.writeUint32(tableEntry.offset);
woffWriter.writeUint32(tableEntry.compLength);
woffWriter.writeUint32(tableEntry.length);
woffWriter.writeUint32(tableEntry.checkSum);
}
// 写表数据
for (i = 0, l = tableEntries.length; i < l; ++i) {
tableEntry = tableEntries[i];
woffWriter.writeBytes(tableEntry.data);
if (tableEntry.compLength % 4) {
woffWriter.writeEmpty(4 - tableEntry.compLength % 4);
}
}
// 写metadata
if (metadata) {
woffWriter.writeBytes(metadata);
if (woffHeader.metaLength % 4) {
woffWriter.writeEmpty(4 - woffHeader.metaLength % 4);
}
}
return woffWriter.getBuffer();
}