fonteditor-core
Version:
fonts (ttf, woff, woff2, eot, svg, otf) parse, write, transform, glyph adjust.
235 lines (217 loc) • 8.75 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _writer = _interopRequireDefault(require("./writer"));
var _directory = _interopRequireDefault(require("./table/directory"));
var _support = _interopRequireDefault(require("./table/support"));
var _checkSum = _interopRequireDefault(require("./util/checkSum"));
var _error = _interopRequireDefault(require("./error"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /**
* @file ttf写入器
* @author mengke01(kekee000@gmail.com)
*/
// 支持写的表, 注意表顺序
var SUPPORT_TABLES = ['OS/2', 'cmap', 'glyf', 'head', 'hhea', 'hmtx', 'loca', 'maxp', 'name', 'post'];
var TTFWriter = exports.default = /*#__PURE__*/function () {
function TTFWriter() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
_classCallCheck(this, TTFWriter);
this.options = {
writeZeroContoursGlyfData: options.writeZeroContoursGlyfData || false,
// 不写入空 glyf 数据
hinting: options.hinting || false,
// 默认不保留hints信息
kerning: options.kerning || false,
// 默认不保留 kernings space 信息
support: options.support // 自定义的导出表结构,可以自己修改某些表项目
};
}
/**
* 处理ttf结构,以便于写
*
* @param {ttfObject} ttf ttf数据结构
*/
return _createClass(TTFWriter, [{
key: "resolveTTF",
value: function resolveTTF(ttf) {
// 头部信息
ttf.version = ttf.version || 0x1;
ttf.numTables = ttf.writeOptions.tables.length;
ttf.entrySelector = Math.floor(Math.log(ttf.numTables) / Math.LN2);
ttf.searchRange = Math.pow(2, ttf.entrySelector) * 16;
ttf.rangeShift = ttf.numTables * 16 - ttf.searchRange;
// 重置校验码
ttf.head.checkSumAdjustment = 0;
ttf.head.magickNumber = 0x5F0F3CF5;
if (typeof ttf.head.created === 'string') {
ttf.head.created = /^\d+$/.test(ttf.head.created) ? +ttf.head.created : Date.parse(ttf.head.created);
}
if (typeof ttf.head.modified === 'string') {
ttf.head.modified = /^\d+$/.test(ttf.head.modified) ? +ttf.head.modified : Date.parse(ttf.head.modified);
}
// 重置日期
if (!ttf.head.created) {
ttf.head.created = Date.now();
}
if (!ttf.head.modified) {
ttf.head.modified = ttf.head.created;
}
var checkUnicodeRepeat = {}; // 检查是否有重复代码点
// 将glyf的代码点按小到大排序
ttf.glyf.forEach(function (glyf, index) {
if (glyf.unicode) {
glyf.unicode = glyf.unicode.sort();
glyf.unicode.forEach(function (u) {
if (checkUnicodeRepeat[u]) {
_error.default.raise({
number: 10200,
data: index
}, index);
} else {
checkUnicodeRepeat[u] = true;
}
});
}
});
}
/**
* 写ttf文件
*
* @param {ttfObject} ttf ttf数据结构
* @return {ArrayBuffer} 字节流
*/
}, {
key: "dump",
value: function dump(ttf) {
// 用来做写入缓存的对象,用完后删掉
ttf.support = Object.assign({}, this.options.support);
// head + directory
var ttfSize = 12 + ttf.numTables * 16;
var ttfHeadOffset = 0; // 记录head的偏移
// 构造tables
ttf.support.tables = [];
ttf.writeOptions.tables.forEach(function (tableName) {
var offset = ttfSize;
var TableClass = _support.default[tableName];
var tableSize = new TableClass().size(ttf); // 原始的表大小
var size = tableSize; // 对齐后的表大小
if (tableName === 'head') {
ttfHeadOffset = offset;
}
// 4字节对齐
if (size % 4) {
size += 4 - size % 4;
}
ttf.support.tables.push({
name: tableName,
checkSum: 0,
offset: offset,
length: tableSize,
size: size
});
ttfSize += size;
});
var writer = new _writer.default(new ArrayBuffer(ttfSize));
// 写头部
writer.writeFixed(ttf.version);
writer.writeUint16(ttf.numTables);
writer.writeUint16(ttf.searchRange);
writer.writeUint16(ttf.entrySelector);
writer.writeUint16(ttf.rangeShift);
// 写表偏移
new _directory.default().write(writer, ttf);
// 写支持的表数据
ttf.support.tables.forEach(function (table) {
var tableStart = writer.offset;
var TableClass = _support.default[table.name];
new TableClass().write(writer, ttf);
if (table.length % 4) {
// 对齐字节
writer.writeEmpty(4 - table.length % 4);
}
// 计算校验和
table.checkSum = (0, _checkSum.default)(writer.getBuffer(), tableStart, table.size);
});
// 重新写入每个表校验和
ttf.support.tables.forEach(function (table, index) {
var offset = 12 + index * 16 + 4;
writer.writeUint32(table.checkSum, offset);
});
// 写入总校验和
var ttfCheckSum = (0xB1B0AFBA - (0, _checkSum.default)(writer.getBuffer()) + 0x100000000) % 0x100000000;
writer.writeUint32(ttfCheckSum, ttfHeadOffset + 8);
delete ttf.writeOptions;
delete ttf.support;
var buffer = writer.getBuffer();
writer.dispose();
return buffer;
}
/**
* 对ttf的表进行评估,标记需要处理的表
*
* @param {Object} ttf ttf对象
*/
}, {
key: "prepareDump",
value: function prepareDump(ttf) {
if (!ttf.glyf || ttf.glyf.length === 0) {
_error.default.raise(10201);
}
if (!ttf['OS/2'] || !ttf.head || !ttf.name) {
_error.default.raise(10204);
}
var tables = SUPPORT_TABLES.slice(0);
ttf.writeOptions = {};
// hinting tables direct copy
if (this.options.hinting) {
['cvt', 'fpgm', 'prep', 'gasp', 'GPOS', 'kern', 'kerx'].forEach(function (table) {
if (ttf[table]) {
tables.push(table);
}
});
}
// copy kerning space table
if (this.options.kerning) {
['GPOS', 'kern', 'kerx'].forEach(function (table) {
if (ttf[table]) {
tables.push(table);
}
});
}
ttf.writeOptions.writeZeroContoursGlyfData = !!this.options.writeZeroContoursGlyfData;
ttf.writeOptions.hinting = !!this.options.hinting;
ttf.writeOptions.kerning = !!this.options.kerning;
ttf.writeOptions.tables = tables.sort();
}
/**
* 写一个ttf字体结构
*
* @param {Object} ttf ttf数据结构
* @return {ArrayBuffer} 缓冲数组
*/
}, {
key: "write",
value: function write(ttf) {
this.prepareDump(ttf);
this.resolveTTF(ttf);
var buffer = this.dump(ttf);
return buffer;
}
/**
* 注销
*/
}, {
key: "dispose",
value: function dispose() {
delete this.options;
}
}]);
}();