fonteditor-core
Version:
fonts (ttf, woff, woff2, eot, svg, otf) parse, write, transform, glyph adjust.
274 lines (257 loc) • 7.24 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = parseGlyf;
var _glyFlag = _interopRequireDefault(require("../../enum/glyFlag"));
var _componentFlag = _interopRequireDefault(require("../../enum/componentFlag"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file 解析glyf轮廓
* @author mengke01(kekee000@gmail.com)
*/
var MAX_INSTRUCTION_LENGTH = 5000; // 设置instructions阈值防止读取错误
var MAX_NUMBER_OF_COORDINATES = 20000; // 设置坐标最大个数阈值,防止glyf读取错误
/**
* 读取简单字形
*
* @param {Reader} reader Reader对象
* @param {Object} glyf 空glyf
* @return {Object} 解析后的glyf
*/
function parseSimpleGlyf(reader, glyf) {
var offset = reader.offset;
// 轮廓点个数
var numberOfCoordinates = glyf.endPtsOfContours[glyf.endPtsOfContours.length - 1] + 1;
// 判断坐标是否超过最大个数
if (numberOfCoordinates > MAX_NUMBER_OF_COORDINATES) {
console.warn('error read glyf coordinates:' + offset);
return glyf;
}
// 获取flag标志
var i;
var length;
var flags = [];
var flag;
i = 0;
while (i < numberOfCoordinates) {
flag = reader.readUint8();
flags.push(flag);
i++;
// 标志位3重复flag
if (flag & _glyFlag.default.REPEAT && i < numberOfCoordinates) {
// 重复个数
var repeat = reader.readUint8();
for (var j = 0; j < repeat; j++) {
flags.push(flag);
i++;
}
}
}
// 坐标集合
var coordinates = [];
var xCoordinates = [];
var prevX = 0;
var x;
for (i = 0, length = flags.length; i < length; ++i) {
x = 0;
flag = flags[i];
// 标志位1
// If set, the corresponding y-coordinate is 1 byte long, not 2
if (flag & _glyFlag.default.XSHORT) {
x = reader.readUint8();
// 标志位5
x = flag & _glyFlag.default.XSAME ? x : -1 * x;
}
// 与上一值一致
else if (flag & _glyFlag.default.XSAME) {
x = 0;
}
// 新值
else {
x = reader.readInt16();
}
prevX += x;
xCoordinates[i] = prevX;
coordinates[i] = {
x: prevX,
y: 0
};
if (flag & _glyFlag.default.ONCURVE) {
coordinates[i].onCurve = true;
}
}
var yCoordinates = [];
var prevY = 0;
var y;
for (i = 0, length = flags.length; i < length; i++) {
y = 0;
flag = flags[i];
if (flag & _glyFlag.default.YSHORT) {
y = reader.readUint8();
y = flag & _glyFlag.default.YSAME ? y : -1 * y;
} else if (flag & _glyFlag.default.YSAME) {
y = 0;
} else {
y = reader.readInt16();
}
prevY += y;
yCoordinates[i] = prevY;
if (coordinates[i]) {
coordinates[i].y = prevY;
}
}
// 计算轮廓集合
if (coordinates.length) {
var endPtsOfContours = glyf.endPtsOfContours;
var contours = [];
contours.push(coordinates.slice(0, endPtsOfContours[0] + 1));
for (i = 1, length = endPtsOfContours.length; i < length; i++) {
contours.push(coordinates.slice(endPtsOfContours[i - 1] + 1, endPtsOfContours[i] + 1));
}
glyf.contours = contours;
}
return glyf;
}
/**
* 读取复合字形
*
* @param {Reader} reader Reader对象
* @param {Object} glyf glyf对象
* @return {Object} glyf对象
*/
function parseCompoundGlyf(reader, glyf) {
glyf.compound = true;
glyf.glyfs = [];
var flags;
var g;
// 读取复杂字形
do {
flags = reader.readUint16();
g = {};
g.flags = flags;
g.glyphIndex = reader.readUint16();
var arg1 = 0;
var arg2 = 0;
var scaleX = 16384;
var scaleY = 16384;
var scale01 = 0;
var scale10 = 0;
if (_componentFlag.default.ARG_1_AND_2_ARE_WORDS & flags) {
arg1 = reader.readInt16();
arg2 = reader.readInt16();
} else {
arg1 = reader.readInt8();
arg2 = reader.readInt8();
}
if (_componentFlag.default.ROUND_XY_TO_GRID & flags) {
arg1 = Math.round(arg1);
arg2 = Math.round(arg2);
}
if (_componentFlag.default.WE_HAVE_A_SCALE & flags) {
scaleX = reader.readInt16();
scaleY = scaleX;
} else if (_componentFlag.default.WE_HAVE_AN_X_AND_Y_SCALE & flags) {
scaleX = reader.readInt16();
scaleY = reader.readInt16();
} else if (_componentFlag.default.WE_HAVE_A_TWO_BY_TWO & flags) {
scaleX = reader.readInt16();
scale01 = reader.readInt16();
scale10 = reader.readInt16();
scaleY = reader.readInt16();
}
if (_componentFlag.default.ARGS_ARE_XY_VALUES & flags) {
g.useMyMetrics = !!flags & _componentFlag.default.USE_MY_METRICS;
g.overlapCompound = !!flags & _componentFlag.default.OVERLAP_COMPOUND;
g.transform = {
a: Math.round(10000 * scaleX / 16384) / 10000,
b: Math.round(10000 * scale01 / 16384) / 10000,
c: Math.round(10000 * scale10 / 16384) / 10000,
d: Math.round(10000 * scaleY / 16384) / 10000,
e: arg1,
f: arg2
};
} else {
g.points = [arg1, arg2];
g.transform = {
a: Math.round(10000 * scaleX / 16384) / 10000,
b: Math.round(10000 * scale01 / 16384) / 10000,
c: Math.round(10000 * scale10 / 16384) / 10000,
d: Math.round(10000 * scaleY / 16384) / 10000,
e: 0,
f: 0
};
}
glyf.glyfs.push(g);
} while (_componentFlag.default.MORE_COMPONENTS & flags);
if (_componentFlag.default.WE_HAVE_INSTRUCTIONS & flags) {
var length = reader.readUint16();
if (length < MAX_INSTRUCTION_LENGTH) {
var instructions = [];
for (var i = 0; i < length; ++i) {
instructions.push(reader.readUint8());
}
glyf.instructions = instructions;
} else {
console.warn(length);
}
}
return glyf;
}
/**
* 解析glyf轮廓
*
* @param {Reader} reader 读取器
* @param {Object} ttf ttf对象
* @param {number=} offset 偏移
* @return {Object} glyf对象
*/
function parseGlyf(reader, ttf, offset) {
if (null != offset) {
reader.seek(offset);
}
var glyf = {};
var i;
var length;
var instructions;
// 边界值
var numberOfContours = reader.readInt16();
glyf.xMin = reader.readInt16();
glyf.yMin = reader.readInt16();
glyf.xMax = reader.readInt16();
glyf.yMax = reader.readInt16();
// 读取简单字形
if (numberOfContours >= 0) {
// endPtsOfConturs
glyf.endPtsOfContours = [];
if (numberOfContours > 0) {
for (i = 0; i < numberOfContours; i++) {
glyf.endPtsOfContours.push(reader.readUint16());
}
} else {
delete glyf.xMin;
delete glyf.yMin;
delete glyf.xMax;
delete glyf.yMax;
}
// instructions
length = reader.readUint16();
if (length) {
// range错误
if (length < MAX_INSTRUCTION_LENGTH) {
instructions = [];
for (i = 0; i < length; ++i) {
instructions.push(reader.readUint8());
}
glyf.instructions = instructions;
} else {
console.warn(length);
}
}
parseSimpleGlyf(reader, glyf);
delete glyf.endPtsOfContours;
} else {
parseCompoundGlyf(reader, glyf);
}
return glyf;
}