将 fonteditor-core 嵌入到项目中,方便后续优化

This commit is contained in:
崮生(子虚) 2026-04-08 21:24:56 +08:00
parent 3163e99534
commit 41c2741e3e
256 changed files with 28276 additions and 1 deletions

View File

@ -15,7 +15,7 @@
"release": "pnpm build && pnpm build_backend && pnpm docker_build && pnpm docker_push"
},
"dependencies": {
"fonteditor-core": "^2.6.3",
"fonteditor-core": "file:./vendor/fonteditor-core",
"solid-js": "^1.9.12",
"web-streams-polyfill": "^4.2.0"
},

21
vendor/fonteditor-core/LICENSE vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 ecomfe
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

200
vendor/fonteditor-core/README.md vendored Normal file
View File

@ -0,0 +1,200 @@
# fonteditor-core
**FontEditor core functions**
[![NPM version][npm-image]][npm-url]
[![Downloads][downloads-image]][npm-url]
## Feature
Read and write sfnt font like ttf, woff, woff2, eot, svg, otf.
- sfnt parse
- read, write, transform fonts
- ttf (read and write)
- woff (read and write)
- woff2 (read and write)
- eot (read and write)
- svg (read and write)
- otf (only read and convert to ttf)
- ttf glyph adjust
- svg to glyph
- ESM compatibility for modern bundlers (Webpack, Rollup, Vite, Next.js, etc.)
- TypeScript support with type definitions
## Usage
```javascript
// read font file
import {createFont} from 'fonteditor-core';
import fs from 'fs';
const buffer = fs.readFileSync('font.ttf');
// read font data, support format:
// - for ttf, otf, woff, woff2, support ArrayBuffer, Buffer
// - for svg, support string or Document(parsed svg)
const font = createFont(buffer, {
// support ttf, woff, woff2, eot, otf, svg
type: 'ttf',
// only read `a`, `b` glyphs
subset: [65, 66],
// read font hinting tables, default false
hinting: true,
// read font kerning tables, default false
kerning: true,
// transform ttf compound glyph to simple
compound2simple: true,
// inflate function for woff
inflate: undefined,
// for svg path
combinePath: false,
});
const fontObject = font.get();
console.log(Object.keys(fontObject));
/* => [ 'version',
'numTables',
'searchRenge',
'entrySelector',
'rengeShift',
'head',
'maxp',
'glyf',
'cmap',
'name',
'hhea',
'post',
'OS/2',
'fpgm',
'cvt',
'prep'
]
*/
// write font file
const buffer = font.write({
// support ttf, woff, woff2, eot, svg
type: 'woff',
// save font hinting tables, default false
hinting: false,
// save font kerning tables, default false
kerning: false,
// write glyf data when simple glyph has no contours, default false
writeZeroContoursGlyfData: false,
// deflate function for woff, eg. pako.deflate
deflate: undefined,
// for user to overwrite head.xMin, head.xMax, head.yMin, head.yMax, hhea etc.
support: {head: {}, hhea: {}}
});
fs.writeFileSync('font.woff', buffer);
// to base64 str
font.toBase64({
// support ttf, woff, woff2, eot, svg
type: 'ttf'
});
// optimize glyphs
font.optimize()
// compound2simple
font.compound2simple()
// sort glyphs
font.sort()
// find glyphs
const result = font.find({
unicode: [65]
});
const result = font.find({
filter: function (glyf) {
return glyf.name === 'icon'
}
});
// merge another font object
font.merge(font1, {
scale: 1
});
```
### Modern ES Module Usage
This library supports both CommonJS and ES Modules. For detailed information on using with modern bundlers, please see [ESM_USAGE.md](./ESM_USAGE.md).
```javascript
// ESM import
import fonteditorCore, { createFont, woff2 } from 'fonteditor-core';
createFont(buffer, options);
```
### woff2
**Notice:** woff2 use wasm build of google woff2, before read and write `woff2`, we should first call `woff2.init()`.
```javascript
import {createFont, woff2} from 'fonteditor-core';
// in nodejs
woff2.init().then(() => {
// read woff2
const font = createFont(buffer, {
type: 'woff2'
});
// write woff2
const buffer = font.write({type: 'woff2'});
});
// in browser
woff2.init('/assets/woff2.wasm').then(() => {
// read woff2
const font = createFont();
// write woff2
const arrayBuffer = font.write({type: 'woff2'});
});
```
## Demo
```
npm run dev
```
## build
```
npm run build
```
## test
```
npm run test
```
## support
Node.js:>= 12.0
Browser: Chrome, Safari
## Related
- [fonteditor](https://github.com/ecomfe/fonteditor)
- [fontmin](https://github.com/ecomfe/fontmin)
- [fonteditor online](https://kekee000.github.io/fonteditor/index.html)
## License
MIT © Fonteditor
[downloads-image]: http://img.shields.io/npm/dm/fonteditor-core.svg
[npm-url]: https://npmjs.org/package/fonteditor-core
[npm-image]: http://img.shields.io/npm/v/fonteditor-core.svg
[travis-url]: https://travis-ci.org/kekee000/fonteditor-core
[travis-image]: http://img.shields.io/travis/kekee000/fonteditor-core.svg

1249
vendor/fonteditor-core/index.d.ts vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
/**
* @file DOM解析器兼容node端和浏览器端
* @author mengke01(kekee000@gmail.com)
*/
/* eslint-disable no-undef */
var _default = exports.default = typeof window !== 'undefined' && window.DOMParser ? window.DOMParser : require('@xmldom/xmldom').DOMParser;

View File

@ -0,0 +1,92 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
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 用于国际化的字符串管理类
* @author mengke01(kekee000@gmail.com)
*/
function appendLanguage(store, languageList) {
languageList.forEach(function (item) {
var language = item[0];
store[language] = Object.assign(store[language] || {}, item[1]);
});
return store;
}
/**
* 管理国际化字符根据lang切换语言版本
*
* @class I18n
* @param {Array} languageList 当前支持的语言列表
* @param {string=} defaultLanguage 默认语言
* languageList = [
* 'en-us', // 语言名称
* langObject // 语言字符串列表
* ]
*/
var I18n = exports.default = /*#__PURE__*/function () {
function I18n(languageList, defaultLanguage) {
_classCallCheck(this, I18n);
this.store = appendLanguage({}, languageList);
this.setLanguage(defaultLanguage || typeof navigator !== 'undefined' && navigator.language && navigator.language.toLowerCase() || 'en-us');
}
/**
* 设置语言
*
* @param {string} language 语言
* @return {this}
*/
return _createClass(I18n, [{
key: "setLanguage",
value: function setLanguage(language) {
if (!this.store[language]) {
language = 'en-us';
}
this.lang = this.store[this.language = language];
return this;
}
/**
* 添加一个语言字符串
*
* @param {string} language 语言
* @param {Object} langObject 语言对象
* @return {this}
*/
}, {
key: "addLanguage",
value: function addLanguage(language, langObject) {
appendLanguage(this.store, [[language, langObject]]);
return this;
}
/**
* 获取当前语言字符串
*
* @param {string} path 语言路径
* @return {string} 语言字符串
*/
}, {
key: "get",
value: function get(path) {
var ref = path.split('.');
var refObject = this.lang;
var level;
while (refObject != null && (level = ref.shift())) {
refObject = refObject[level];
}
return refObject != null ? refObject : '';
}
}]);
}();

View File

@ -0,0 +1,80 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = ajaxFile;
exports.loadFile = loadFile;
/**
* @file ajax获取文本数据
* @author mengke01(kekee000@gmail.com)
*/
/**
* ajax获取数据
*
* @param {Object} options 参数选项
* @param {string=} options.type 类型
* @param {string=} options.method method
* @param {Function=} options.onSuccess 成功回调
* @param {Function=} options.onError 失败回调
* @param {Object=} options.params 参数集合
*/
function ajaxFile(options) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
var status = xhr.status;
if (status >= 200 && status < 300 || status === 304) {
if (options.onSuccess) {
if (options.type === 'binary') {
var buffer = xhr.responseBlob || xhr.response;
options.onSuccess(buffer);
} else if (options.type === 'xml') {
options.onSuccess(xhr.responseXML);
} else if (options.type === 'json') {
options.onSuccess(JSON.parse(xhr.responseText));
} else {
options.onSuccess(xhr.responseText);
}
}
} else if (options.onError) {
options.onError(xhr, xhr.status);
}
}
};
var method = (options.method || 'GET').toUpperCase();
var params = null;
if (options.params) {
var str = [];
Object.keys(options.params).forEach(function (key) {
str.push(key + '=' + encodeURIComponent(options.params[key]));
});
str = str.join('&');
if (method === 'GET') {
options.url += (options.url.indexOf('?') === -1 ? '?' : '&') + str;
} else {
params = str;
}
}
xhr.open(method, options.url, true);
if (options.type === 'binary') {
xhr.responseType = 'arraybuffer';
}
xhr.send(params);
}
function loadFile(url) {
var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'binary';
return new Promise(function (resolve, reject) {
ajaxFile({
type: type,
url: url,
onSuccess: function onSuccess(buffer) {
resolve(buffer);
},
onError: function onError(e) {
reject(e);
}
});
});
}

View File

@ -0,0 +1,234 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.clone = clone;
exports.curry = curry;
exports.debounce = debounce;
exports.equals = equals;
exports.generic = generic;
exports.isArray = isArray;
exports.isDate = isDate;
exports.isEmptyObject = isEmptyObject;
exports.isFunction = isFunction;
exports.isObject = isObject;
exports.isString = isString;
exports.overwrite = overwrite;
exports.throttle = throttle;
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); }
/**
* @file 语言相关函数
* @author mengke01(kekee000@gmail.com)
*/
function isArray(obj) {
return obj != null && toString.call(obj).slice(8, -1) === 'Array';
}
function isObject(obj) {
return obj != null && toString.call(obj).slice(8, -1) === 'Object';
}
function isString(obj) {
return obj != null && toString.call(obj).slice(8, -1) === 'String';
}
function isFunction(obj) {
return obj != null && toString.call(obj).slice(8, -1) === 'Function';
}
function isDate(obj) {
return obj != null && toString.call(obj).slice(8, -1) === 'Date';
}
function isEmptyObject(object) {
for (var name in object) {
// eslint-disable-next-line no-prototype-builtins
if (object.hasOwnProperty(name)) {
return false;
}
}
return true;
}
/**
* 为函数提前绑定前置参数柯里化
*
* @see http://en.wikipedia.org/wiki/Currying
* @param {Function} fn 要绑定的函数
* @param {...Array} cargs cargs
* @return {Function}
*/
function curry(fn) {
for (var _len = arguments.length, cargs = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
cargs[_key - 1] = arguments[_key];
}
return function () {
for (var _len2 = arguments.length, rargs = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
rargs[_key2] = arguments[_key2];
}
var args = cargs.concat(rargs);
// eslint-disable-next-line no-invalid-this
return fn.apply(this, args);
};
}
/**
* 方法静态化, 反绑定延迟绑定
*
* @param {Function} method 待静态化的方法
* @return {Function} 静态化包装后方法
*/
function generic(method) {
return function () {
for (var _len3 = arguments.length, fargs = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
fargs[_key3] = arguments[_key3];
}
return Function.call.apply(method, fargs);
};
}
/**
* 设置覆盖相关的属性值
*
* @param {Object} thisObj 覆盖对象
* @param {Object} thatObj 值对象
* @param {Array.<string>} fields 字段
* @return {Object} thisObj
*/
function overwrite(thisObj, thatObj, fields) {
if (!thatObj) {
return thisObj;
}
// 这里`fields`未指定则仅overwrite自身可枚举的字段指定`fields`则不做限制
fields = fields || Object.keys(thatObj);
fields.forEach(function (field) {
// 拷贝对象
if (thisObj[field] && _typeof(thisObj[field]) === 'object' && thatObj[field] && _typeof(thatObj[field]) === 'object') {
overwrite(thisObj[field], thatObj[field]);
} else {
thisObj[field] = thatObj[field];
}
});
return thisObj;
}
/**
* 深复制对象仅复制数据
*
* @param {Object} source 源数据
* @return {Object} 复制的数据
*/
function clone(source) {
if (!source || _typeof(source) !== 'object') {
return source;
}
var cloned = source;
if (isArray(source)) {
cloned = source.slice().map(clone);
} else if (isObject(source) && 'isPrototypeOf' in source) {
cloned = {};
for (var _i = 0, _Object$keys = Object.keys(source); _i < _Object$keys.length; _i++) {
var key = _Object$keys[_i];
cloned[key] = clone(source[key]);
}
}
return cloned;
}
// Returns a function, that, when invoked, will only be triggered at most once
// during a given window of time.
// @see underscore.js
function throttle(func, wait) {
var context;
var args;
var timeout;
var result;
var previous = 0;
var later = function later() {
previous = new Date();
timeout = null;
result = func.apply(context, args);
};
return function () {
var now = new Date();
var remaining = wait - (now - previous);
// eslint-disable-next-line no-invalid-this
context = this;
if (remaining <= 0) {
clearTimeout(timeout);
timeout = null;
previous = now;
for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
args[_key4] = arguments[_key4];
}
result = func.apply(context, args);
} else if (!timeout) {
timeout = setTimeout(later, remaining);
}
return result;
};
}
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
// @see underscore.js
function debounce(func, wait, immediate) {
var timeout;
var result;
return function () {
for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {
args[_key5] = arguments[_key5];
}
// eslint-disable-next-line no-invalid-this
var context = this;
var later = function later() {
timeout = null;
if (!immediate) {
result = func.apply(context, args);
}
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) {
result = func.apply(context, args);
}
return result;
};
}
/**
* 判断两个对象的字段是否相等
*
* @param {Object} thisObj 要比较的对象
* @param {Object} thatObj 参考对象
* @param {Array} fields 指定字段
* @return {boolean} 是否相等
*/
function equals(thisObj, thatObj, fields) {
if (thisObj === thatObj) {
return true;
}
if (thisObj == null && thatObj == null) {
return true;
}
if (thisObj == null && thatObj != null || thisObj != null && thatObj == null) {
return false;
}
// 这里`fields`未指定则仅overwrite自身可枚举的字段指定`fields`则不做限制
fields = fields || (_typeof(thisObj) === 'object' ? Object.keys(thisObj) : []);
if (!fields.length) {
return thisObj === thatObj;
}
var equal = true;
for (var i = 0, l = fields.length, field; equal && i < l; i++) {
field = fields[i];
if (thisObj[field] && _typeof(thisObj[field]) === 'object' && thatObj[field] && _typeof(thatObj[field]) === 'object') {
equal = equal && equals(thisObj[field], thatObj[field]);
} else {
equal = equal && thisObj[field] === thatObj[field];
}
}
return equal;
}

View File

@ -0,0 +1,94 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
/**
* @file 字符串相关的函数
* @author mengke01(kekee000@gmail.com)
*/
var _default = exports.default = {
/**
* HTML解码字符串
*
* @param {string} source 源字符串
* @return {string}
*/
decodeHTML: function decodeHTML(source) {
var str = String(source).replace(/&quot;/g, '"').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&amp;/g, '&');
// 处理转义的中文和实体字符
return str.replace(/&#([\d]+);/g, function ($0, $1) {
return String.fromCodePoint(parseInt($1, 10));
});
},
/**
* HTML编码字符串
*
* @param {string} source 源字符串
* @return {string}
*/
encodeHTML: function encodeHTML(source) {
return String(source).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
},
/**
* 获取string字节长度
*
* @param {string} source 源字符串
* @return {number} 长度
*/
getLength: function getLength(source) {
// eslint-disable-next-line no-control-regex
return String(source).replace(/[^\x00-\xff]/g, '11').length;
},
/**
* 字符串格式化支持如 ${xxx.xxx} 的语法
*
* @param {string} source 模板字符串
* @param {Object} data 数据
* @return {string} 格式化后字符串
*/
format: function format(source, data) {
return source.replace(/\$\{([\w.]+)\}/g, function ($0, $1) {
var ref = $1.split('.');
var refObject = data;
var level;
while (refObject != null && (level = ref.shift())) {
refObject = refObject[level];
}
return refObject != null ? refObject : '';
});
},
/**
* 使用指定字符填充字符串,默认`0`
*
* @param {string} str 字符串
* @param {number} size 填充到的大小
* @param {string=} ch 填充字符
* @return {string} 字符串
*/
pad: function pad(str, size, ch) {
str = String(str);
if (str.length > size) {
return str.slice(str.length - size);
}
return new Array(size - str.length + 1).join(ch || '0') + str;
},
/**
* 获取字符串哈希编码
*
* @param {string} str 字符串
* @return {number} 哈希值
*/
hashcode: function hashcode(str) {
if (!str) {
return 0;
}
var hash = 0;
for (var i = 0, l = str.length; i < l; i++) {
hash = 0x7FFFFFFFF & hash * 31 + str.charCodeAt(i);
}
return hash;
}
};

View File

@ -0,0 +1,165 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.computePath = exports.computeBounding = void 0;
exports.computePathBox = computePathBox;
exports.quadraticBezier = void 0;
var _pathIterator = _interopRequireDefault(require("./pathIterator"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file 计算曲线包围盒
* @author mengke01(kekee000@gmail.com)
*
* modify from:
* zrender
* https://github.com/ecomfe/zrender/blob/master/src/tool/computeBoundingBox.js
*/
/**
* 计算包围盒
*
* @param {Array} points 点集
* @return {Object} bounding box
*/
function computeBoundingBox(points) {
if (points.length === 0) {
return false;
}
var left = points[0].x;
var right = points[0].x;
var top = points[0].y;
var bottom = points[0].y;
for (var i = 1; i < points.length; i++) {
var p = points[i];
if (p.x < left) {
left = p.x;
}
if (p.x > right) {
right = p.x;
}
if (p.y < top) {
top = p.y;
}
if (p.y > bottom) {
bottom = p.y;
}
}
return {
x: left,
y: top,
width: right - left,
height: bottom - top
};
}
/**
* 计算二阶贝塞尔曲线的包围盒
* http://pissang.net/blog/?p=91
*
* @param {Object} p0 p0
* @param {Object} p1 p1
* @param {Object} p2 p2
* @return {Object} bound对象
*/
function computeQuadraticBezierBoundingBox(p0, p1, p2) {
// Find extremities, where derivative in x dim or y dim is zero
var tmp = p0.x + p2.x - 2 * p1.x;
// p1 is center of p0 and p2 in x dim
var t1;
if (tmp === 0) {
t1 = 0.5;
} else {
t1 = (p0.x - p1.x) / tmp;
}
tmp = p0.y + p2.y - 2 * p1.y;
// p1 is center of p0 and p2 in y dim
var t2;
if (tmp === 0) {
t2 = 0.5;
} else {
t2 = (p0.y - p1.y) / tmp;
}
t1 = Math.max(Math.min(t1, 1), 0);
t2 = Math.max(Math.min(t2, 1), 0);
var ct1 = 1 - t1;
var ct2 = 1 - t2;
var x1 = ct1 * ct1 * p0.x + 2 * ct1 * t1 * p1.x + t1 * t1 * p2.x;
var y1 = ct1 * ct1 * p0.y + 2 * ct1 * t1 * p1.y + t1 * t1 * p2.y;
var x2 = ct2 * ct2 * p0.x + 2 * ct2 * t2 * p1.x + t2 * t2 * p2.x;
var y2 = ct2 * ct2 * p0.y + 2 * ct2 * t2 * p1.y + t2 * t2 * p2.y;
return computeBoundingBox([p0, p2, {
x: x1,
y: y1
}, {
x: x2,
y: y2
}]);
}
/**
* 计算曲线包围盒
*
* @private
* @param {...Array} args 坐标点集, 支持多个path
* @return {Object} {x, y, width, height}
*/
function computePathBoundingBox() {
var points = [];
var iterator = function iterator(c, p0, p1, p2) {
if (c === 'L') {
points.push(p0);
points.push(p1);
} else if (c === 'Q') {
var bound = computeQuadraticBezierBoundingBox(p0, p1, p2);
points.push(bound);
points.push({
x: bound.x + bound.width,
y: bound.y + bound.height
});
}
};
if (arguments.length === 1) {
(0, _pathIterator.default)(arguments.length <= 0 ? undefined : arguments[0], function (c, p0, p1, p2) {
if (c === 'L') {
points.push(p0);
points.push(p1);
} else if (c === 'Q') {
var bound = computeQuadraticBezierBoundingBox(p0, p1, p2);
points.push(bound);
points.push({
x: bound.x + bound.width,
y: bound.y + bound.height
});
}
});
} else {
for (var i = 0, l = arguments.length; i < l; i++) {
(0, _pathIterator.default)(i < 0 || arguments.length <= i ? undefined : arguments[i], iterator);
}
}
return computeBoundingBox(points);
}
/**
* 计算曲线点边界
*
* @private
* @param {...Array} args path对象, 支持多个path
* @return {Object} {x, y, width, height}
*/
function computePathBox() {
var points = [];
if (arguments.length === 1) {
points = arguments.length <= 0 ? undefined : arguments[0];
} else {
for (var i = 0, l = arguments.length; i < l; i++) {
Array.prototype.splice.apply(points, [points.length, 0].concat(i < 0 || arguments.length <= i ? undefined : arguments[i]));
}
}
return computeBoundingBox(points);
}
var computeBounding = exports.computeBounding = computeBoundingBox;
var quadraticBezier = exports.quadraticBezier = computeQuadraticBezierBoundingBox;
var computePath = exports.computePath = computePathBoundingBox;

View File

@ -0,0 +1,223 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = getArc;
var _bezierCubic2Q = _interopRequireDefault(require("../math/bezierCubic2Q2"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file 使用插值法获取椭圆弧度以支持svg arc命令
* @author mengke01(kekee000@gmail.com)
*
* modify from:
* https://github.com/fontello/svgpath/blob/master/lib/a2c.js
* references:
* http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
*/
var TAU = Math.PI * 2;
function vectorAngle(ux, uy, vx, vy) {
// Calculate an angle between two vectors
var sign = ux * vy - uy * vx < 0 ? -1 : 1;
var umag = Math.sqrt(ux * ux + uy * uy);
var vmag = Math.sqrt(ux * ux + uy * uy);
var dot = ux * vx + uy * vy;
var div = dot / (umag * vmag);
if (div > 1 || div < -1) {
// rounding errors, e.g. -1.0000000000000002 can screw up this
div = Math.max(div, -1);
div = Math.min(div, 1);
}
return sign * Math.acos(div);
}
function correctRadii(midx, midy, rx, ry) {
// Correction of out-of-range radii
rx = Math.abs(rx);
ry = Math.abs(ry);
var Λ = midx * midx / (rx * rx) + midy * midy / (ry * ry);
if (Λ > 1) {
rx *= Math.sqrt(Λ);
ry *= Math.sqrt(Λ);
}
return [rx, ry];
}
function getArcCenter(x1, y1, x2, y2, fa, fs, rx, ry, sin, cos) {
// Convert from endpoint to center parameterization,
// see http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
// Step 1.
//
// Moving an ellipse so origin will be the middlepoint between our two
// points. After that, rotate it to line up ellipse axes with coordinate
// axes.
//
var x1p = cos * (x1 - x2) / 2 + sin * (y1 - y2) / 2;
var y1p = -sin * (x1 - x2) / 2 + cos * (y1 - y2) / 2;
var rx_sq = rx * rx;
var ry_sq = ry * ry;
var x1p_sq = x1p * x1p;
var y1p_sq = y1p * y1p;
// Step 2.
//
// Compute coordinates of the centre of this ellipse (cx', cy')
// in the new coordinate system.
//
var radicant = rx_sq * ry_sq - rx_sq * y1p_sq - ry_sq * x1p_sq;
if (radicant < 0) {
// due to rounding errors it might be e.g. -1.3877787807814457e-17
radicant = 0;
}
radicant /= rx_sq * y1p_sq + ry_sq * x1p_sq;
radicant = Math.sqrt(radicant) * (fa === fs ? -1 : 1);
var cxp = radicant * rx / ry * y1p;
var cyp = radicant * -ry / rx * x1p;
// Step 3.
//
// Transform back to get centre coordinates (cx, cy) in the original
// coordinate system.
//
var cx = cos * cxp - sin * cyp + (x1 + x2) / 2;
var cy = sin * cxp + cos * cyp + (y1 + y2) / 2;
// Step 4.
//
// Compute angles (θ1, Δθ).
//
var v1x = (x1p - cxp) / rx;
var v1y = (y1p - cyp) / ry;
var v2x = (-x1p - cxp) / rx;
var v2y = (-y1p - cyp) / ry;
var θ1 = vectorAngle(1, 0, v1x, v1y);
var Δθ = vectorAngle(v1x, v1y, v2x, v2y);
if (fs === 0 && Δθ > 0) {
Δθ -= TAU;
}
if (fs === 1 && Δθ < 0) {
Δθ += TAU;
}
return [cx, cy, θ1, Δθ];
}
function approximateUnitArc(θ1, Δθ) {
// Approximate one unit arc segment with bézier curves,
// see http://math.stackexchange.com/questions/873224/
// calculate-control-points-of-cubic-bezier-curve-approximating-a-part-of-a-circle
var α = 4 / 3 * Math.tan(Δθ / 4);
var x1 = Math.cos(θ1);
var y1 = Math.sin(θ1);
var x2 = Math.cos(θ1 + Δθ);
var y2 = Math.sin(θ1 + Δθ);
return [x1, y1, x1 - y1 * α, y1 + x1 * α, x2 + y2 * α, y2 - x2 * α, x2, y2];
}
function a2c(x1, y1, x2, y2, fa, fs, rx, ry, φ) {
var sin = Math.sin(φ * TAU / 360);
var cos = Math.cos(φ * TAU / 360);
// Make sure radii are valid
//
var x1p = cos * (x1 - x2) / 2 + sin * (y1 - y2) / 2;
var y1p = -sin * (x1 - x2) / 2 + cos * (y1 - y2) / 2;
if (x1p === 0 && y1p === 0) {
// we're asked to draw line to itself
return [];
}
if (rx === 0 || ry === 0) {
// one of the radii is zero
return [];
}
var radii = correctRadii(x1p, y1p, rx, ry);
rx = radii[0];
ry = radii[1];
// Get center parameters (cx, cy, θ1, Δθ)
//
var cc = getArcCenter(x1, y1, x2, y2, fa, fs, rx, ry, sin, cos);
var result = [];
var θ1 = cc[2];
var Δθ = cc[3];
// Split an arc to multiple segments, so each segment
// will be less than τ/4 (= 90°)
//
var segments = Math.max(Math.ceil(Math.abs(Δθ) / (TAU / 4)), 1);
Δθ /= segments;
for (var i = 0; i < segments; i++) {
result.push(approximateUnitArc(θ1, Δθ));
θ1 += Δθ;
}
// We have a bezier approximation of a unit circle,
// now need to transform back to the original ellipse
//
return result.map(function (curve) {
for (var _i = 0; _i < curve.length; _i += 2) {
var x = curve[_i + 0];
var y = curve[_i + 1];
// scale
x *= rx;
y *= ry;
// rotate
var xp = cos * x - sin * y;
var yp = sin * x + cos * y;
// translate
curve[_i + 0] = xp + cc[0];
curve[_i + 1] = yp + cc[1];
}
return curve;
});
}
/**
* 获取椭圆弧度
*
* @param {number} rx 椭圆长半轴
* @param {number} ry 椭圆短半轴
* @param {number} angle 旋转角度
* @param {number} largeArc 是否大圆弧
* @param {number} sweep 是否延伸圆弧
* @param {Object} p0 分割点1
* @param {Object} p1 分割点2
* @return {Array} 分割后的路径
*/
function getArc(rx, ry, angle, largeArc, sweep, p0, p1) {
var result = a2c(p0.x, p0.y, p1.x, p1.y, largeArc, sweep, rx, ry, angle);
var path = [];
if (result.length) {
path.push({
x: result[0][0],
y: result[0][1],
onCurve: true
});
// 将三次曲线转换成二次曲线
result.forEach(function (c) {
var q2Array = (0, _bezierCubic2Q.default)({
x: c[0],
y: c[1]
}, {
x: c[2],
y: c[3]
}, {
x: c[4],
y: c[5]
}, {
x: c[6],
y: c[7]
});
q2Array[0][2].onCurve = true;
path.push(q2Array[0][1]);
path.push(q2Array[0][2]);
if (q2Array[1]) {
q2Array[1][2].onCurve = true;
path.push(q2Array[1][1]);
path.push(q2Array[1][2]);
}
});
}
return path;
}

View File

@ -0,0 +1,44 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.mul = mul;
exports.multiply = multiply;
/**
* @file matrix变换操作
* @author mengke01(kekee000@gmail.com)
*/
/**
* 仿射矩阵相乘
*
* @param {Array=} matrix1 矩阵1
* @param {Array=} matrix2 矩阵2
* @return {Array} 新矩阵
*/
function mul() {
var matrix1 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [1, 0, 0, 1];
var matrix2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [1, 0, 0, 1];
// 旋转变换 4 个参数
if (matrix1.length === 4) {
return [matrix1[0] * matrix2[0] + matrix1[2] * matrix2[1], matrix1[1] * matrix2[0] + matrix1[3] * matrix2[1], matrix1[0] * matrix2[2] + matrix1[2] * matrix2[3], matrix1[1] * matrix2[2] + matrix1[3] * matrix2[3]];
}
// 旋转位移变换, 6 个参数
return [matrix1[0] * matrix2[0] + matrix1[2] * matrix2[1], matrix1[1] * matrix2[0] + matrix1[3] * matrix2[1], matrix1[0] * matrix2[2] + matrix1[2] * matrix2[3], matrix1[1] * matrix2[2] + matrix1[3] * matrix2[3], matrix1[0] * matrix2[4] + matrix1[2] * matrix2[5] + matrix1[4], matrix1[1] * matrix2[4] + matrix1[3] * matrix2[5] + matrix1[5]];
}
/**
* 多个仿射矩阵相乘
*
* @param {...Array} matrixs matrix array
* @return {Array} 新矩阵
*/
function multiply() {
var result = arguments.length <= 0 ? undefined : arguments[0];
for (var i = 1, matrix; matrix = i < 0 || arguments.length <= i ? undefined : arguments[i]; i++) {
result = mul(result, matrix);
}
return result;
}

View File

@ -0,0 +1,59 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
/**
* @file 圆路径集合逆时针
* @author mengke01(kekee000@gmail.com)
*/
var _default = exports.default = [{
x: 582,
y: 0
}, {
x: 758,
y: 75
}, {
x: 890,
y: 208
}, {
x: 965,
y: 384
}, {
x: 965,
y: 583
}, {
x: 890,
y: 760
}, {
x: 758,
y: 891
}, {
x: 582,
y: 966
}, {
x: 383,
y: 966
}, {
x: 207,
y: 891
}, {
x: 75,
y: 760
}, {
x: 0,
y: 583
}, {
x: 0,
y: 384
}, {
x: 75,
y: 208
}, {
x: 207,
y: 75
}, {
x: 383,
y: 0
}];

View File

@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = pathAdjust;
/**
* @file 调整路径缩放和平移
* @author mengke01(kekee000@gmail.com)
*/
/**
* 对path坐标进行调整
*
* @param {Object} contour 坐标点
* @param {number} scaleX x缩放比例
* @param {number} scaleY y缩放比例
* @param {number} offsetX x偏移
* @param {number} offsetY y偏移
*
* @return {Object} contour 坐标点
*/
function pathAdjust(contour, scaleX, scaleY, offsetX, offsetY) {
scaleX = scaleX === undefined ? 1 : scaleX;
scaleY = scaleY === undefined ? 1 : scaleY;
var x = offsetX || 0;
var y = offsetY || 0;
var p;
for (var i = 0, l = contour.length; i < l; i++) {
p = contour[i];
p.x = scaleX * (p.x + x);
p.y = scaleY * (p.y + y);
}
return contour;
}

View File

@ -0,0 +1,32 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = pathCeil;
/**
* @file 对路径进行四舍五入
* @author mengke01(kekee000@gmail.com)
*/
/**
* 对path坐标进行调整
*
* @param {Array} contour 轮廓点数组
* @param {number} point 四舍五入的点数
* @return {Object} contour 坐标点
*/
function pathCeil(contour, point) {
var p;
for (var i = 0, l = contour.length; i < l; i++) {
p = contour[i];
if (!point) {
p.x = Math.round(p.x);
p.y = Math.round(p.y);
} else {
p.x = Number(p.x.toFixed(point));
p.y = Number(p.y.toFixed(point));
}
}
return contour;
}

View File

@ -0,0 +1,70 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = pathIterator;
/**
* @file 遍历路径的路径集合包括segment和 bezier curve
* @author mengke01(kekee000@gmail.com)
*/
/**
* 遍历路径的路径集合
*
* @param {Array} contour 坐标点集
* @param {Function} callBack 回调函数参数集合command, p0, p1, p2, i
* p0, p1, p2 直线或者贝塞尔曲线参数
* i 当前遍历的点
* 其中command = L 或者 Q表示直线或者贝塞尔曲线
*/
function pathIterator(contour, callBack) {
var curPoint;
var prevPoint;
var nextPoint;
var cursorPoint; // cursorPoint 为当前单个绘制命令的起点
for (var i = 0, l = contour.length; i < l; i++) {
curPoint = contour[i];
prevPoint = i === 0 ? contour[l - 1] : contour[i - 1];
nextPoint = i === l - 1 ? contour[0] : contour[i + 1];
// 起始坐标
if (i === 0) {
if (curPoint.onCurve) {
cursorPoint = curPoint;
} else if (prevPoint.onCurve) {
cursorPoint = prevPoint;
} else {
cursorPoint = {
x: (prevPoint.x + curPoint.x) / 2,
y: (prevPoint.y + curPoint.y) / 2
};
}
}
// 直线
if (curPoint.onCurve && nextPoint.onCurve) {
if (false === callBack('L', curPoint, nextPoint, 0, i)) {
break;
}
cursorPoint = nextPoint;
} else if (!curPoint.onCurve) {
if (nextPoint.onCurve) {
if (false === callBack('Q', cursorPoint, curPoint, nextPoint, i)) {
break;
}
cursorPoint = nextPoint;
} else {
var last = {
x: (curPoint.x + nextPoint.x) / 2,
y: (curPoint.y + nextPoint.y) / 2
};
if (false === callBack('Q', cursorPoint, curPoint, last, i)) {
break;
}
cursorPoint = last;
}
}
}
}

View File

@ -0,0 +1,42 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = pathRotate;
/**
* @file 路径旋转
* @author mengke01(kekee000@gmail.com)
*/
/**
* 对path坐标进行调整
*
* @param {Object} contour 坐标点
* @param {number} angle 角度
* @param {number} centerX x偏移
* @param {number} centerY y偏移
*
* @return {Object} contour 坐标点
*/
function pathRotate(contour, angle, centerX, centerY) {
angle = angle === undefined ? 0 : angle;
var x = centerX || 0;
var y = centerY || 0;
var cos = Math.cos(angle);
var sin = Math.sin(angle);
var px;
var py;
var p;
// x1=cos(angle)*x-sin(angle)*y;
// y1=cos(angle)*y+sin(angle)*x;
for (var i = 0, l = contour.length; i < l; i++) {
p = contour[i];
px = cos * (p.x - x) - sin * (p.y - y);
py = cos * (p.y - y) + sin * (p.x - x);
p.x = px + x;
p.y = py + y;
}
return contour;
}

View File

@ -0,0 +1,45 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = pathSkew;
/**
* @file path倾斜变换
* @author mengke01(kekee000@gmail.com)
*/
/**
* path倾斜变换
*
* @param {Object} contour 坐标点
* @param {number} angle 角度
* @param {number} offsetX x偏移
* @param {number} offsetY y偏移
*
* @return {Object} contour 坐标点
*/
function pathSkew(contour, angle, offsetX, offsetY) {
angle = angle === undefined ? 0 : angle;
var x = offsetX || 0;
var tan = Math.tan(angle);
var p;
var i;
var l;
// x 平移
if (x === 0) {
for (i = 0, l = contour.length; i < l; i++) {
p = contour[i];
p.x += tan * (p.y - offsetY);
}
}
// y平移
else {
for (i = 0, l = contour.length; i < l; i++) {
p = contour[i];
p.y += tan * (p.x - offsetX);
}
}
return contour;
}

View File

@ -0,0 +1,32 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = pathSkewX;
var _computeBoundingBox = require("./computeBoundingBox");
/**
* @file 按X轴平移变换, 变换中心为图像中心点
* @author mengke01(kekee000@gmail.com)
*/
/**
* path倾斜变换
*
* @param {Object} contour 坐标点
* @param {number} angle 角度
*
* @return {Object} contour 坐标点
*/
function pathSkewX(contour, angle) {
angle = angle === undefined ? 0 : angle;
var y = (0, _computeBoundingBox.computePath)(contour).y;
var tan = Math.tan(angle);
var p;
// x 平移
for (var i = 0, l = contour.length; i < l; i++) {
p = contour[i];
p.x += tan * (p.y - y);
}
return contour;
}

View File

@ -0,0 +1,32 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = pathSkewY;
var _computeBoundingBox = require("./computeBoundingBox");
/**
* @file 按Y轴平移变换, 变换中心为图像中心点
* @author mengke01(kekee000@gmail.com)
*/
/**
* path倾斜变换
*
* @param {Object} contour 坐标点
* @param {number} angle 角度
*
* @return {Object} contour 坐标点
*/
function pathSkewY(contour, angle) {
angle = angle === undefined ? 0 : angle;
var x = (0, _computeBoundingBox.computePath)(contour).x;
var tan = Math.tan(angle);
var p;
// y 平移
for (var i = 0, l = contour.length; i < l; i++) {
p = contour[i];
p.y += tan * (p.x - x);
}
return contour;
}

View File

@ -0,0 +1,46 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = transform;
/**
* @file 对轮廓进行transform变换
* @author mengke01(kekee000@gmail.com)
*
* 参考资料
* http://blog.csdn.net/henren555/article/details/9699449
*
* |X| |a c e| |x|
* |Y| = |b d f| * |y|
* |1| |0 0 1| |1|
*
* X = x * a + y * c + e
* Y = x * b + y * d + f
*/
/**
* 图形仿射矩阵变换
*
* @param {Array.<Object>} contour 轮廓点
* @param {number} a m11
* @param {number} b m12
* @param {number} c m21
* @param {number} d m22
* @param {number} e dx
* @param {number} f dy
* @return {Array.<Object>} contour 轮廓点
*/
function transform(contour, a, b, c, d, e, f) {
var x;
var y;
var p;
for (var i = 0, l = contour.length; i < l; i++) {
p = contour[i];
x = p.x;
y = p.y;
p.x = x * a + y * c + e;
p.y = x * b + y * d + f;
}
return contour;
}

View File

@ -0,0 +1,170 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.clone = clone;
exports.deInterpolate = deInterpolate;
exports.getPathHash = getPathHash;
exports.interpolate = interpolate;
exports.isClockWise = isClockWise;
exports.makeLink = makeLink;
exports.removeOverlapPoints = removeOverlapPoints;
exports.scale = scale;
var _util = require("./util");
/**
* @file 路径相关的函数集合
* @author mengke01(kekee000@gmail.com)
*/
/**
* 对路径进行插值补全省略的点
*
* @param {Array} path 路径
* @return {Array} 路径
*/
function interpolate(path) {
var newPath = [];
for (var i = 0, l = path.length; i < l; i++) {
var next = i === l - 1 ? 0 : i + 1;
newPath.push(path[i]);
// 插值
if (!path[i].onCurve && !path[next].onCurve) {
newPath.push({
x: (path[i].x + path[next].x) / 2,
y: (path[i].y + path[next].y) / 2,
onCurve: true
});
}
}
return newPath;
}
/**
* 去除路径中的插值点
*
* @param {Array} path 路径
* @return {Array} 路径
*/
function deInterpolate(path) {
var newPath = [];
for (var i = 0, l = path.length; i < l; i++) {
var next = i === l - 1 ? 0 : i + 1;
var prev = i === 0 ? l - 1 : i - 1;
// 插值
if (!path[prev].onCurve && path[i].onCurve && !path[next].onCurve && Math.abs(2 * path[i].x - path[prev].x - path[next].x) < 0.001 && Math.abs(2 * path[i].y - path[prev].y - path[next].y) < 0.001) {
continue;
}
newPath.push(path[i]);
}
return newPath;
}
/**
* 判断路径的方向是否顺时针
*
* see:
* http://debian.fmi.uni-sofia.bg/~sergei/cgsr/docs/clockwise.htm
*
* @param {Array} path 路径
* @return {number} 0 无方向 1 clockwise, -1 counter clockwise
*/
function isClockWise(path) {
if (path.length < 3) {
return 0;
}
var zCount = 0;
for (var i = 0, l = path.length; i < l; i++) {
var cur = path[i];
var prev = i === 0 ? path[l - 1] : path[i - 1];
var next = i === l - 1 ? path[0] : path[i + 1];
var z = (cur.x - prev.x) * (next.y - cur.y) - (cur.y - prev.y) * (next.x - cur.x);
if (z < 0) {
zCount--;
} else if (z > 0) {
zCount++;
}
}
return zCount === 0 ? 0 : zCount < 0 ? 1 : -1;
}
/**
* 获取路径哈希
*
* @param {Array} path 路径数组
* @return {number} 哈希值
*/
function getPathHash(path) {
var hash = 0;
var seed = 131;
path.forEach(function (p) {
hash = 0x7FFFFFFF & hash * seed + (0, _util.getPointHash)(p) + (p.onCurve ? 1 : 0);
});
return hash;
}
/**
* 移除重复点
*
* @param {Array} points 点集合
* @return {Array} 移除后点集合
*/
function removeOverlapPoints(points) {
var hash = {};
var ret = [];
for (var i = 0, l = points.length; i < l; i++) {
var hashcode = points[i].x * 31 + points[i].y;
if (!hash[hashcode]) {
ret.push(points[i]);
hash[hashcode] = 1;
}
}
return ret;
}
/**
* 对path进行双向链表连接
*
* @param {Array} path 轮廓数组
* @return {Array} path
*/
function makeLink(path) {
for (var i = 0, l = path.length; i < l; i++) {
var cur = path[i];
var prev = i === 0 ? path[l - 1] : path[i - 1];
var next = i === l - 1 ? path[0] : path[i + 1];
cur.index = i;
cur.next = next;
cur.prev = prev;
}
return path;
}
/**
* 对path进行缩放
*
* @param {Array} path 轮廓数组
* @param {number} ratio 缩放大小
*
* @return {Array} path
*/
function scale(path, ratio) {
for (var i = 0, l = path.length; i < l; i++) {
var cur = path[i];
cur.x *= ratio;
cur.y *= ratio;
}
return path;
}
function clone(path) {
return path ? path.map(function (p) {
var newP = {
x: p.x,
y: p.y
};
if (p.onCurve) {
newP.onCurve = true;
}
return newP;
}) : path;
}

View File

@ -0,0 +1,91 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _computeBoundingBox = require("./computeBoundingBox");
var _pathAdjust = _interopRequireDefault(require("./pathAdjust"));
var _pathRotate = _interopRequireDefault(require("./pathRotate"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } /**
* @file 路径组变化函数
* @author mengke01(kekee000@gmail.com)
*/
/**
* 翻转路径
*
* @param {Array} paths 路径数组
* @param {number} xScale x翻转
* @param {number} yScale y翻转
* @return {Array} 变换后的路径
*/
function mirrorPaths(paths, xScale, yScale) {
var _computePath = _computeBoundingBox.computePath.apply(void 0, _toConsumableArray(paths)),
x = _computePath.x,
y = _computePath.y,
width = _computePath.width,
height = _computePath.height;
if (xScale === -1) {
paths.forEach(function (p) {
(0, _pathAdjust.default)(p, -1, 1, -x, 0);
(0, _pathAdjust.default)(p, 1, 1, x + width, 0);
p.reverse();
});
}
if (yScale === -1) {
paths.forEach(function (p) {
(0, _pathAdjust.default)(p, 1, -1, 0, -y);
(0, _pathAdjust.default)(p, 1, 1, 0, y + height);
p.reverse();
});
}
return paths;
}
var _default = exports.default = {
/**
* 旋转路径
*
* @param {Array} paths 路径数组
* @param {number} angle 弧度
* @return {Array} 变换后的路径
*/
rotate: function rotate(paths, angle) {
if (!angle) {
return paths;
}
var bound = _computeBoundingBox.computePath.apply(void 0, _toConsumableArray(paths));
var cx = bound.x + bound.width / 2;
var cy = bound.y + bound.height / 2;
paths.forEach(function (p) {
(0, _pathRotate.default)(p, angle, cx, cy);
});
return paths;
},
/**
* 路径组变换
*
* @param {Array} paths 路径数组
* @param {number} x x 方向缩放
* @param {number} y y 方向缩放
* @return {Array} 变换后的路径
*/
move: function move(paths, x, y) {
var bound = _computeBoundingBox.computePath.apply(void 0, _toConsumableArray(paths));
paths.forEach(function (path) {
(0, _pathAdjust.default)(path, 1, 1, x - bound.x, y - bound.y);
});
return paths;
},
mirror: function mirror(paths) {
return mirrorPaths(paths, -1, 1);
},
flip: function flip(paths) {
return mirrorPaths(paths, 1, -1);
}
};

View File

@ -0,0 +1,63 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = reducePath;
/**
* @file 缩减path大小去除冗余节点
* @author mengke01(kekee000@gmail.com)
*/
/**
* 判断点是否多余的点
*
* @param {Object} prev 上一个
* @param {Object} p 当前
* @param {Object} next 下一个
* @return {boolean}
*/
function redundant(prev, p, next) {
// 是否重合的点, 只有两个点同在曲线上或者同不在曲线上移出
if ((p.onCurve && next.onCurve || !p.onCurve && !next.onCurve) && Math.pow(p.x - next.x, 2) + Math.pow(p.y - next.y, 2) <= 1) {
return true;
}
// 三点同线 检查直线点
if (p.onCurve && prev.onCurve && next.onCurve && Math.abs((next.y - p.y) * (prev.x - p.x) - (prev.y - p.y) * (next.x - p.x)) <= 0.001) {
return true;
}
// 三点同线 检查控制点
if (!p.onCurve && prev.onCurve && next.onCurve && Math.abs((next.y - p.y) * (prev.x - p.x) - (prev.y - p.y) * (next.x - p.x)) <= 0.001) {
return true;
}
return false;
}
/**
* 缩减glyf去除冗余节点
*
* @param {Array} contour 路径对象
* @return {Array} 路径对象
*/
function reducePath(contour) {
if (!contour.length) {
return contour;
}
var prev;
var next;
var p;
for (var i = contour.length - 1, last = i; i >= 0; i--) {
// 这里注意逆序
p = contour[i];
next = i === last ? contour[0] : contour[i + 1];
prev = i === 0 ? contour[last] : contour[i - 1];
if (redundant(prev, p, next)) {
contour.splice(i, 1);
last--;
continue;
}
}
return contour;
}

View File

@ -0,0 +1,88 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ceil = ceil;
exports.ceilPoint = ceilPoint;
exports.getPointHash = getPointHash;
exports.isPointInBound = isPointInBound;
exports.isPointOverlap = isPointOverlap;
/**
* @file grahpics点相关工具箱
* @author mengke01(kekee000@gmail.com)
*/
/**
* 将点进行误差舍入
*
* @param {Object} p 点对象
* @return {Object}
*/
function ceilPoint(p) {
var t = p.x;
// 处理形如 4.99999 = 5, 5.00001 = 5的情况
if (Math.abs(Math.round(t) - t) < 0.00002) {
p.x = Math.round(t);
} else {
p.x = Math.round(p.x * 100000) / 100000;
}
t = p.y;
if (Math.abs(Math.round(t) - t) < 0.00005) {
p.y = Math.round(t);
} else {
p.y = Math.round(p.y * 100000) / 100000;
}
return p;
}
/**
* 将数值进行误差舍入
*
* @param {Object} x 数值
* @return {number}
*/
function ceil(x) {
if (Math.abs(Math.round(x) - x) < 0.00002) {
return Math.round(x);
}
return Math.round(x * 100000) / 100000;
}
/**
* 判断点是否在bounding box内部
*
* @param {Object} bound bounding box对象
* @param {Object} p 点对象
* @param {boolean=} fixed 是否四舍五入
* @return {boolean} 是否
*/
function isPointInBound(bound, p, fixed) {
if (fixed) {
return ceil(p.x) <= ceil(bound.x + bound.width) && ceil(p.x) >= ceil(bound.x) && ceil(p.y) <= ceil(bound.y + bound.height) && ceil(p.y) >= ceil(bound.y);
}
return p.x <= bound.x + bound.width && p.x >= bound.x && p.y <= bound.y + bound.height && p.y >= bound.y;
}
/**
* 判断点是否重合
*
* @param {Object} p0 p0
* @param {Object} p1 p1
* @return {boolean} 是否
*/
function isPointOverlap(p0, p1) {
return ceil(p0.x) === ceil(p1.x) && ceil(p0.y) === ceil(p1.y);
}
/**
* 获取点的hash值
*
* @param {Object} p p
* @param {Object} p1 p1
* @return {number}
*/
function getPointHash(p) {
return Math.floor(7 * Math.floor(p.x * 10) + 131 * Math.floor(p.y * 100));
}

179
vendor/fonteditor-core/lib/main.esm.js vendored Normal file
View File

@ -0,0 +1,179 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "Font", {
enumerable: true,
get: function get() {
return _font.Font;
}
});
Object.defineProperty(exports, "OTFReader", {
enumerable: true,
get: function get() {
return _otfreader.default;
}
});
Object.defineProperty(exports, "Reader", {
enumerable: true,
get: function get() {
return _reader.default;
}
});
Object.defineProperty(exports, "TTF", {
enumerable: true,
get: function get() {
return _ttf.default;
}
});
Object.defineProperty(exports, "TTFReader", {
enumerable: true,
get: function get() {
return _ttfreader.default;
}
});
Object.defineProperty(exports, "TTFWriter", {
enumerable: true,
get: function get() {
return _ttfwriter.default;
}
});
Object.defineProperty(exports, "Writer", {
enumerable: true,
get: function get() {
return _writer.default;
}
});
Object.defineProperty(exports, "createFont", {
enumerable: true,
get: function get() {
return _font.createFont;
}
});
exports.default = void 0;
Object.defineProperty(exports, "eot2ttf", {
enumerable: true,
get: function get() {
return _eot2ttf.default;
}
});
Object.defineProperty(exports, "otf2ttfobject", {
enumerable: true,
get: function get() {
return _otf2ttfobject.default;
}
});
Object.defineProperty(exports, "svg2ttfobject", {
enumerable: true,
get: function get() {
return _svg2ttfobject.default;
}
});
exports.toBuffer = exports.toArrayBuffer = void 0;
Object.defineProperty(exports, "ttf2base64", {
enumerable: true,
get: function get() {
return _ttf2base.default;
}
});
Object.defineProperty(exports, "ttf2eot", {
enumerable: true,
get: function get() {
return _ttf2eot.default;
}
});
Object.defineProperty(exports, "ttf2icon", {
enumerable: true,
get: function get() {
return _ttf2icon.default;
}
});
Object.defineProperty(exports, "ttf2svg", {
enumerable: true,
get: function get() {
return _ttf2svg.default;
}
});
Object.defineProperty(exports, "ttf2woff", {
enumerable: true,
get: function get() {
return _ttf2woff.default;
}
});
Object.defineProperty(exports, "ttftowoff2", {
enumerable: true,
get: function get() {
return _ttftowoff.default;
}
});
Object.defineProperty(exports, "woff2", {
enumerable: true,
get: function get() {
return _index.default;
}
});
Object.defineProperty(exports, "woff2tottf", {
enumerable: true,
get: function get() {
return _woff2tottf.default;
}
});
Object.defineProperty(exports, "woff2ttf", {
enumerable: true,
get: function get() {
return _woff2ttf.default;
}
});
var _font = require("./ttf/font");
var _ttf = _interopRequireDefault(require("./ttf/ttf"));
var _ttfreader = _interopRequireDefault(require("./ttf/ttfreader"));
var _ttfwriter = _interopRequireDefault(require("./ttf/ttfwriter"));
var _ttf2eot = _interopRequireDefault(require("./ttf/ttf2eot"));
var _eot2ttf = _interopRequireDefault(require("./ttf/eot2ttf"));
var _ttf2woff = _interopRequireDefault(require("./ttf/ttf2woff"));
var _woff2ttf = _interopRequireDefault(require("./ttf/woff2ttf"));
var _ttf2svg = _interopRequireDefault(require("./ttf/ttf2svg"));
var _svg2ttfobject = _interopRequireDefault(require("./ttf/svg2ttfobject"));
var _reader = _interopRequireDefault(require("./ttf/reader"));
var _writer = _interopRequireDefault(require("./ttf/writer"));
var _otfreader = _interopRequireDefault(require("./ttf/otfreader"));
var _otf2ttfobject = _interopRequireDefault(require("./ttf/otf2ttfobject"));
var _ttf2base = _interopRequireDefault(require("./ttf/ttf2base64"));
var _ttf2icon = _interopRequireDefault(require("./ttf/ttf2icon"));
var _ttftowoff = _interopRequireDefault(require("./ttf/ttftowoff2"));
var _woff2tottf = _interopRequireDefault(require("./ttf/woff2tottf"));
var _index = _interopRequireDefault(require("../woff2/index"));
var _buffer = _interopRequireDefault(require("./nodejs/buffer"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file 主函数
* @author mengke01(kekee000@gmail.com)
*/
var toArrayBuffer = exports.toArrayBuffer = _buffer.default.toArrayBuffer;
var toBuffer = exports.toBuffer = _buffer.default.toBuffer;
var _default = exports.default = {
createFont: _font.createFont,
Font: _font.Font,
TTF: _ttf.default,
TTFReader: _ttfreader.default,
TTFWriter: _ttfwriter.default,
ttf2eot: _ttf2eot.default,
eot2ttf: _eot2ttf.default,
ttf2woff: _ttf2woff.default,
woff2ttf: _woff2ttf.default,
ttf2svg: _ttf2svg.default,
svg2ttfobject: _svg2ttfobject.default,
Reader: _reader.default,
Writer: _writer.default,
OTFReader: _otfreader.default,
otf2ttfobject: _otf2ttfobject.default,
ttf2base64: _ttf2base.default,
ttf2icon: _ttf2icon.default,
ttftowoff2: _ttftowoff.default,
woff2tottf: _woff2tottf.default,
woff2: _index.default,
toArrayBuffer: _buffer.default.toArrayBuffer,
toBuffer: _buffer.default.toBuffer
};

82
vendor/fonteditor-core/lib/main.js vendored Normal file
View File

@ -0,0 +1,82 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "Font", {
enumerable: true,
get: function get() {
return _font.Font;
}
});
Object.defineProperty(exports, "createFont", {
enumerable: true,
get: function get() {
return _font.createFont;
}
});
exports.default = void 0;
Object.defineProperty(exports, "woff2", {
enumerable: true,
get: function get() {
return _index.default;
}
});
var _font = require("./ttf/font");
var _ttf = _interopRequireDefault(require("./ttf/ttf"));
var _ttfreader = _interopRequireDefault(require("./ttf/ttfreader"));
var _ttfwriter = _interopRequireDefault(require("./ttf/ttfwriter"));
var _ttf2eot = _interopRequireDefault(require("./ttf/ttf2eot"));
var _eot2ttf = _interopRequireDefault(require("./ttf/eot2ttf"));
var _ttf2woff = _interopRequireDefault(require("./ttf/ttf2woff"));
var _woff2ttf = _interopRequireDefault(require("./ttf/woff2ttf"));
var _ttf2svg = _interopRequireDefault(require("./ttf/ttf2svg"));
var _svg2ttfobject = _interopRequireDefault(require("./ttf/svg2ttfobject"));
var _reader = _interopRequireDefault(require("./ttf/reader"));
var _writer = _interopRequireDefault(require("./ttf/writer"));
var _otfreader = _interopRequireDefault(require("./ttf/otfreader"));
var _otf2ttfobject = _interopRequireDefault(require("./ttf/otf2ttfobject"));
var _ttf2base = _interopRequireDefault(require("./ttf/ttf2base64"));
var _ttf2icon = _interopRequireDefault(require("./ttf/ttf2icon"));
var _ttftowoff = _interopRequireDefault(require("./ttf/ttftowoff2"));
var _woff2tottf = _interopRequireDefault(require("./ttf/woff2tottf"));
var _index = _interopRequireDefault(require("../woff2/index"));
var _buffer = _interopRequireDefault(require("./nodejs/buffer"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file 主函数
* @author mengke01(kekee000@gmail.com)
*/
var modules = {
createFont: _font.createFont,
Font: _font.Font,
TTF: _ttf.default,
TTFReader: _ttfreader.default,
TTFWriter: _ttfwriter.default,
ttf2eot: _ttf2eot.default,
eot2ttf: _eot2ttf.default,
ttf2woff: _ttf2woff.default,
woff2ttf: _woff2ttf.default,
ttf2svg: _ttf2svg.default,
svg2ttfobject: _svg2ttfobject.default,
Reader: _reader.default,
Writer: _writer.default,
OTFReader: _otfreader.default,
otf2ttfobject: _otf2ttfobject.default,
ttf2base64: _ttf2base.default,
ttf2icon: _ttf2icon.default,
ttftowoff2: _ttftowoff.default,
woff2tottf: _woff2tottf.default,
woff2: _index.default,
toArrayBuffer: _buffer.default.toArrayBuffer,
toBuffer: _buffer.default.toBuffer
};
// Export named exports for ESM
// Export default object
var _default = exports.default = modules;
if (typeof exports !== 'undefined') {
// eslint-disable-next-line import/no-commonjs
module.exports = modules;
}

View File

@ -0,0 +1,71 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = bezierCubic2Q2;
/**
* @file 三次贝塞尔转二次贝塞尔
* @author mengke01(kekee000@gmail.com)
*
* references:
* https://github.com/search?utf8=%E2%9C%93&q=svg2ttf
* http://www.caffeineowl.com/graphics/2d/vectorial/cubic2quad01.html
*
*/
function toQuad(p1, c1, c2, p2) {
// Quad control point is (3*c2 - p2 + 3*c1 - p1)/4
var x = (3 * c2.x - p2.x + 3 * c1.x - p1.x) / 4;
var y = (3 * c2.y - p2.y + 3 * c1.y - p1.y) / 4;
return [p1, {
x: x,
y: y
}, p2];
}
/**
* 三次贝塞尔转二次贝塞尔
*
* @param {Object} p1 开始点
* @param {Object} c1 控制点1
* @param {Object} c2 控制点2
* @param {Object} p2 结束点
* @return {Array} 二次贝塞尔控制点
*/
function bezierCubic2Q2(p1, c1, c2, p2) {
// 判断极端情况,控制点和起止点一样
if (p1.x === c1.x && p1.y === c1.y && c2.x === p2.x && c2.y === p2.y) {
return [[p1, {
x: (p1.x + p2.x) / 2,
y: (p1.y + p2.y) / 2
}, p2]];
}
var mx = p2.x - 3 * c2.x + 3 * c1.x - p1.x;
var my = p2.y - 3 * c2.y + 3 * c1.y - p1.y;
// control points near
if (mx * mx + my * my <= 4) {
return [toQuad(p1, c1, c2, p2)];
}
// Split to 2 qubic beziers by midpoints
// (p2 + 3*c2 + 3*c1 + p1)/8
var mp = {
x: (p2.x + 3 * c2.x + 3 * c1.x + p1.x) / 8,
y: (p2.y + 3 * c2.y + 3 * c1.y + p1.y) / 8
};
return [toQuad(p1, {
x: (p1.x + c1.x) / 2,
y: (p1.y + c1.y) / 2
}, {
x: (p1.x + 2 * c1.x + c2.x) / 4,
y: (p1.y + 2 * c1.y + c2.y) / 4
}, mp), toQuad(mp, {
x: (p2.x + c1.x + 2 * c2.x) / 4,
y: (p2.y + c1.y + 2 * c2.y) / 4
}, {
x: (p2.x + c2.x) / 2,
y: (p2.y + c2.y) / 2
}, p2)];
}

View File

@ -0,0 +1,45 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
/**
* @file Buffer和ArrayBuffer转换
* @author mengke01(kekee000@gmail.com)
*/
/* eslint-disable no-undef */
var _default = exports.default = {
/**
* Buffer转换成ArrayBuffer
*
* @param {Buffer} buffer 缓冲数组
* @return {ArrayBuffer}
*/
toArrayBuffer: function toArrayBuffer(buffer) {
var length = buffer.length;
var view = new DataView(new ArrayBuffer(length), 0, length);
for (var i = 0, l = length; i < l; i++) {
view.setUint8(i, buffer[i], false);
}
return view.buffer;
},
/**
* ArrayBuffer转换成Buffer
*
* @param {ArrayBuffer} arrayBuffer 缓冲数组
* @return {Buffer}
*/
toBuffer: function toBuffer(arrayBuffer) {
if (Array.isArray(arrayBuffer)) {
return Buffer.from(arrayBuffer);
}
var length = arrayBuffer.byteLength;
var view = new DataView(arrayBuffer, 0, length);
var buffer = Buffer.alloc(length);
for (var i = 0, l = length; i < l; i++) {
buffer[i] = view.getUint8(i, false);
}
return buffer;
}
};

View File

@ -0,0 +1,23 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
/**
* @file 默认的ttf字体配置
* @author mengke01(kekee000@gmail.com)
*/
var _default = exports.default = {
// 默认的字体编码
fontId: 'fonteditor',
// 默认的名字集合
name: {
// 默认的字体家族
fontFamily: 'fonteditor',
fontSubFamily: 'Medium',
uniqueSubFamily: 'FontEditor 1.0 : fonteditor',
version: 'Version 1.0; FontEditor (v1.0)',
postScriptName: 'fonteditor'
}
};

View File

@ -0,0 +1,183 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
/**
* @file 空的ttf格式json对象
* @author mengke01(kekee000@gmail.com)
*/
/* eslint-disable */
var _default = exports.default = {
"version": 1,
"numTables": 10,
"searchRange": 128,
"entrySelector": 3,
"rangeShift": 64,
"head": {
"version": 1,
"fontRevision": 1,
"checkSumAdjustment": 0,
"magickNumber": 1594834165,
"flags": 11,
"unitsPerEm": 1024,
"created": 1428940800000,
"modified": 1428940800000,
"xMin": 34,
"yMin": 0,
"xMax": 306,
"yMax": 682,
"macStyle": 0,
"lowestRecPPEM": 8,
"fontDirectionHint": 2,
"indexToLocFormat": 0,
"glyphDataFormat": 0
},
"glyf": [{
"contours": [[{
"x": 34,
"y": 0,
"onCurve": true
}, {
"x": 34,
"y": 682,
"onCurve": true
}, {
"x": 306,
"y": 682,
"onCurve": true
}, {
"x": 306,
"y": 0,
"onCurve": true
}], [{
"x": 68,
"y": 34,
"onCurve": true
}, {
"x": 272,
"y": 34,
"onCurve": true
}, {
"x": 272,
"y": 648,
"onCurve": true
}, {
"x": 68,
"y": 648,
"onCurve": true
}]],
"xMin": 34,
"yMin": 0,
"xMax": 306,
"yMax": 682,
"advanceWidth": 374,
"leftSideBearing": 34,
"name": ".notdef"
}],
"cmap": {},
"name": {
"fontFamily": "fonteditor",
"fontSubFamily": "Medium",
"uniqueSubFamily": "FontEditor 1.0 : fonteditor",
"version": "Version 1.0 ; FontEditor (v0.0.1)",
"postScriptName": "fonteditor",
"fullName": "fonteditor"
},
"hhea": {
"version": 1,
"ascent": 812,
"descent": -212,
"lineGap": 92,
"advanceWidthMax": 374,
"minLeftSideBearing": 34,
"minRightSideBearing": 68,
"xMaxExtent": 306,
"caretSlopeRise": 1,
"caretSlopeRun": 0,
"caretOffset": 0,
"reserved0": 0,
"reserved1": 0,
"reserved2": 0,
"reserved3": 0,
"metricDataFormat": 0,
"numOfLongHorMetrics": 1
},
"post": {
"italicAngle": 0,
"postoints": 65411,
"underlinePosition": 50,
"underlineThickness": 0,
"isFixedPitch": 0,
"minMemType42": 0,
"maxMemType42": 0,
"minMemType1": 0,
"maxMemType1": 1,
"format": 2
},
"maxp": {
"version": 1.0,
"numGlyphs": 0,
"maxPoints": 0,
"maxContours": 0,
"maxCompositePoints": 0,
"maxCompositeContours": 0,
"maxZones": 0,
"maxTwilightPoints": 0,
"maxStorage": 0,
"maxFunctionDefs": 0,
"maxStackElements": 0,
"maxSizeOfInstructions": 0,
"maxComponentElements": 0,
"maxComponentDepth": 0
},
"OS/2": {
"version": 4,
"xAvgCharWidth": 1031,
"usWeightClass": 400,
"usWidthClass": 5,
"fsType": 0,
"ySubscriptXSize": 665,
"ySubscriptYSize": 716,
"ySubscriptXOffset": 0,
"ySubscriptYOffset": 143,
"ySuperscriptXSize": 665,
"ySuperscriptYSize": 716,
"ySuperscriptXOffset": 0,
"ySuperscriptYOffset": 491,
"yStrikeoutSize": 51,
"yStrikeoutPosition": 265,
"sFamilyClass": 0,
"bFamilyType": 2,
"bSerifStyle": 0,
"bWeight": 6,
"bProportion": 3,
"bContrast": 0,
"bStrokeVariation": 0,
"bArmStyle": 0,
"bLetterform": 0,
"bMidline": 0,
"bXHeight": 0,
"ulUnicodeRange1": 1,
"ulUnicodeRange2": 268435456,
"ulUnicodeRange3": 0,
"ulUnicodeRange4": 0,
"achVendID": "PfEd",
"fsSelection": 192,
"usFirstCharIndex": 65535,
"usLastCharIndex": -1,
"sTypoAscender": 812,
"sTypoDescender": -212,
"sTypoLineGap": 92,
"usWinAscent": 812,
"usWinDescent": 212,
"ulCodePageRange1": 1,
"ulCodePageRange2": 0,
"sxHeight": 792,
"sCapHeight": 0,
"usDefaultChar": 0,
"usBreakChar": 32,
"usMaxContext": 1
}
};

View File

@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
/**
* @file 复合图元标记位
* @author mengke01(kekee000@gmail.com)
*
* 复合图元标记位
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6glyf.html
*/
var _default = exports.default = {
ARG_1_AND_2_ARE_WORDS: 0x01,
ARGS_ARE_XY_VALUES: 0x02,
ROUND_XY_TO_GRID: 0x04,
WE_HAVE_A_SCALE: 0x08,
RESERVED: 0x10,
MORE_COMPONENTS: 0x20,
WE_HAVE_AN_X_AND_Y_SCALE: 0x40,
WE_HAVE_A_TWO_BY_TWO: 0x80,
WE_HAVE_INSTRUCTIONS: 0x100,
USE_MY_METRICS: 0x200,
OVERLAP_COMPOUND: 0x400,
SCALED_COMPONENT_OFFSET: 0x800,
UNSCALED_COMPONENT_OFFSET: 0x1000
};

View File

@ -0,0 +1,33 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.win = exports.mac = void 0;
/**
* @file Unicode Platform-specific Encoding Identifiers
* @author mengke01(kekee000@gmail.com)
*/
// mac encoding id
var mac = exports.mac = {
'Default': 0,
// default use
'Version1.1': 1,
'ISO10646': 2,
'UnicodeBMP': 3,
'UnicodenonBMP': 4,
'UnicodeVariationSequences': 5,
'FullUnicodecoverage': 6
};
// windows encoding id
var win = exports.win = {
Symbol: 0,
UCS2: 1,
// default use
ShiftJIS: 2,
PRC: 3,
BigFive: 4,
Johab: 5,
UCS4: 6
};

View File

@ -0,0 +1,29 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
/**
* @file 轮廓标记位
* @author mengke01(kekee000@gmail.com)
*
* see:
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6glyf.html
*/
var _default = exports.default = {
ONCURVE: 0x01,
// on curve ,off curve
XSHORT: 0x02,
// x-Short Vector
YSHORT: 0x04,
// y-Short Vector
REPEAT: 0x08,
// next byte is flag repeat count
XSAME: 0x10,
// This x is same (Positive x-Short vector)
YSAME: 0x20,
// This y is same (Positive y-Short vector)
Reserved1: 0x40,
Reserved2: 0x80
};

View File

@ -0,0 +1,40 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
/**
* @file ttf `name`编码表
* @author mengke01(kekee000@gmail.com)
*/
var nameId = {
0: 'copyright',
1: 'fontFamily',
2: 'fontSubFamily',
3: 'uniqueSubFamily',
4: 'fullName',
5: 'version',
6: 'postScriptName',
7: 'tradeMark',
8: 'manufacturer',
9: 'designer',
10: 'description',
11: 'urlOfFontVendor',
12: 'urlOfFontDesigner',
13: 'licence',
14: 'urlOfLicence',
16: 'preferredFamily',
17: 'preferredSubFamily',
18: 'compatibleFull',
19: 'sampleText'
};
// 反转names
var nameIdHash = {};
Object.keys(nameId).forEach(function (id) {
nameIdHash[nameId[id]] = +id;
});
nameId.names = nameIdHash;
var _default = exports.default = nameId;

View File

@ -0,0 +1,25 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
/**
* @file 字体外观分类器
* @author mengke01(kekee000@gmail.com)
*
* @see:
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6OS2.html
*/
var _default = exports.default = {
bFamilyType: ['Any', 'No Fit', 'Text and Display', 'Script', 'Decorative', 'Pictorial'],
bSerifStyle: ['Any', 'No Fit', 'Cove', 'Obtuse Cove', 'Square Cove', 'Obtuse Square Cove', 'Square', 'Thin', 'Bone', 'Exaggerated', 'Triangle', 'Normal Sans', 'Obtuse Sans', 'Perp Sans', 'Flared', 'Rounded'],
bWeight: ['Any', 'No Fit', 'Very Light', 'Light', 'Thin', 'Book', 'Medium', 'Demi', 'Bold', 'Heavy', 'Black', 'Nord'],
bProportion: ['Any', 'No Fit', 'Old Style', 'Modern', 'Even Width', 'Expanded', 'Condensed', 'Very Expanded', 'Very Condensed', 'Monospaced'],
bContrast: ['Any', 'No Fit', 'None', 'Very Low', 'Low', 'Medium Low', 'Medium', 'Medium High', 'High', 'Very High'],
bStrokeVariation: ['Any', 'No Fit', 'Gradual/Diagonal', 'Gradual/Transitional', 'Gradual/Vertical', 'Gradual/Horizontal', 'Rapid/Vertical', 'Rapid/Horizontal', 'Instant/Vertical'],
bArmStyle: ['Any', 'No Fit', 'Straight Arms/Horizontal', 'Straight Arms/Wedge', 'Straight Arms/Vertical', 'Straight Arms/Single Serif', 'Straight Arms/Double Serif', 'Non-Straight Arms/Horizontal', 'Non-Straight Arms/Wedge', 'Non-Straight Arms/Vertical', 'Non-Straight Arms/Single Serif', 'Non-Straight Arms/Double Serif'],
bLetterform: ['Any', 'No Fit', 'Normal/Contact', 'Normal/Weighted', 'Normal/Boxed', 'Normal/Flattened', 'Normal/Rounded', 'Normal/Off Center', 'Normal/Square', 'Oblique/Contact', 'Oblique/Weighted', 'Oblique/Boxed', 'Oblique/Flattened', 'Oblique/Rounded', 'Oblique/Off Center', 'Oblique/Square'],
bMidline: ['Any', 'No Fit', 'Standard/Trimmed', 'Standard/Pointed', 'Standard/Serifed', 'High/Trimmed', 'High/Pointed', 'High/Serifed', 'Constant/Trimmed', 'Constant/Pointed', 'Constant/Serifed', 'Low/Trimmed', 'Low/Pointed', 'Low/Serifed'],
bXHeight: ['Any', 'No Fit', 'Constant/Small', 'Constant/Standard', 'Constant/Large', 'Ducking/Small', 'Ducking/Standard', 'Ducking/Large']
};

View File

@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
/**
* @file 字体所属平台
* @author mengke01(kekee000@gmail.com)
*/
var _default = exports.default = {
Unicode: 0,
Macintosh: 1,
// mac
reserved: 2,
Microsoft: 3 // win
};

View File

@ -0,0 +1,273 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
/**
* @file Mac glyf命名表
* @author mengke01(kekee000@gmail.com)
*
* see:
* http://www.microsoft.com/typography/otspec/WGL4.htm
*/
var _default = exports.default = {
0: '.notdef',
1: '.null',
2: 'nonmarkingreturn',
3: 'space',
4: 'exclam',
5: 'quotedbl',
6: 'numbersign',
7: 'dollar',
8: 'percent',
9: 'ampersand',
10: 'quotesingle',
11: 'parenleft',
12: 'parenright',
13: 'asterisk',
14: 'plus',
15: 'comma',
16: 'hyphen',
17: 'period',
18: 'slash',
19: 'zero',
20: 'one',
21: 'two',
22: 'three',
23: 'four',
24: 'five',
25: 'six',
26: 'seven',
27: 'eight',
28: 'nine',
29: 'colon',
30: 'semicolon',
31: 'less',
32: 'equal',
33: 'greater',
34: 'question',
35: 'at',
36: 'A',
37: 'B',
38: 'C',
39: 'D',
40: 'E',
41: 'F',
42: 'G',
43: 'H',
44: 'I',
45: 'J',
46: 'K',
47: 'L',
48: 'M',
49: 'N',
50: 'O',
51: 'P',
52: 'Q',
53: 'R',
54: 'S',
55: 'T',
56: 'U',
57: 'V',
58: 'W',
59: 'X',
60: 'Y',
61: 'Z',
62: 'bracketleft',
63: 'backslash',
64: 'bracketright',
65: 'asciicircum',
66: 'underscore',
67: 'grave',
68: 'a',
69: 'b',
70: 'c',
71: 'd',
72: 'e',
73: 'f',
74: 'g',
75: 'h',
76: 'i',
77: 'j',
78: 'k',
79: 'l',
80: 'm',
81: 'n',
82: 'o',
83: 'p',
84: 'q',
85: 'r',
86: 's',
87: 't',
88: 'u',
89: 'v',
90: 'w',
91: 'x',
92: 'y',
93: 'z',
94: 'braceleft',
95: 'bar',
96: 'braceright',
97: 'asciitilde',
98: 'Adieresis',
99: 'Aring',
100: 'Ccedilla',
101: 'Eacute',
102: 'Ntilde',
103: 'Odieresis',
104: 'Udieresis',
105: 'aacute',
106: 'agrave',
107: 'acircumflex',
108: 'adieresis',
109: 'atilde',
110: 'aring',
111: 'ccedilla',
112: 'eacute',
113: 'egrave',
114: 'ecircumflex',
115: 'edieresis',
116: 'iacute',
117: 'igrave',
118: 'icircumflex',
119: 'idieresis',
120: 'ntilde',
121: 'oacute',
122: 'ograve',
123: 'ocircumflex',
124: 'odieresis',
125: 'otilde',
126: 'uacute',
127: 'ugrave',
128: 'ucircumflex',
129: 'udieresis',
130: 'dagger',
131: 'degree',
132: 'cent',
133: 'sterling',
134: 'section',
135: 'bullet',
136: 'paragraph',
137: 'germandbls',
138: 'registered',
139: 'copyright',
140: 'trademark',
141: 'acute',
142: 'dieresis',
143: 'notequal',
144: 'AE',
145: 'Oslash',
146: 'infinity',
147: 'plusminus',
148: 'lessequal',
149: 'greaterequal',
150: 'yen',
151: 'mu',
152: 'partialdiff',
153: 'summation',
154: 'product',
155: 'pi',
156: 'integral',
157: 'ordfeminine',
158: 'ordmasculine',
159: 'Omega',
160: 'ae',
161: 'oslash',
162: 'questiondown',
163: 'exclamdown',
164: 'logicalnot',
165: 'radical',
166: 'florin',
167: 'approxequal',
168: 'Delta',
169: 'guillemotleft',
170: 'guillemotright',
171: 'ellipsis',
172: 'nonbreakingspace',
173: 'Agrave',
174: 'Atilde',
175: 'Otilde',
176: 'OE',
177: 'oe',
178: 'endash',
179: 'emdash',
180: 'quotedblleft',
181: 'quotedblright',
182: 'quoteleft',
183: 'quoteright',
184: 'divide',
185: 'lozenge',
186: 'ydieresis',
187: 'Ydieresis',
188: 'fraction',
189: 'currency',
190: 'guilsinglleft',
191: 'guilsinglright',
192: 'fi',
193: 'fl',
194: 'daggerdbl',
195: 'periodcentered',
196: 'quotesinglbase',
197: 'quotedblbase',
198: 'perthousand',
199: 'Acircumflex',
200: 'Ecircumflex',
201: 'Aacute',
202: 'Edieresis',
203: 'Egrave',
204: 'Iacute',
205: 'Icircumflex',
206: 'Idieresis',
207: 'Igrave',
208: 'Oacute',
209: 'Ocircumflex',
210: 'apple',
211: 'Ograve',
212: 'Uacute',
213: 'Ucircumflex',
214: 'Ugrave',
215: 'dotlessi',
216: 'circumflex',
217: 'tilde',
218: 'macron',
219: 'breve',
220: 'dotaccent',
221: 'ring',
222: 'cedilla',
223: 'hungarumlaut',
224: 'ogonek',
225: 'caron',
226: 'Lslash',
227: 'lslash',
228: 'Scaron',
229: 'scaron',
230: 'Zcaron',
231: 'zcaron',
232: 'brokenbar',
233: 'Eth',
234: 'eth',
235: 'Yacute',
236: 'yacute',
237: 'Thorn',
238: 'thorn',
239: 'minus',
240: 'multiply',
241: 'onesuperior',
242: 'twosuperior',
243: 'threesuperior',
244: 'onehalf',
245: 'onequarter',
246: 'threequarters',
247: 'franc',
248: 'Gbreve',
249: 'gbreve',
250: 'Idotaccent',
251: 'Scedilla',
252: 'scedilla',
253: 'Cacute',
254: 'cacute',
255: 'Ccaron',
256: 'ccaron',
257: 'dcroat'
};

View File

@ -0,0 +1,303 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
/**
* @file unicode 编码与postName对照表
* @author mengke01(kekee000@gmail.com)
*
* see:
* http://www.microsoft.com/typography/otspec/WGL4.htm
*/
var _default = exports.default = {
0: 1,
1: 1,
2: 1,
3: 1,
4: 1,
5: 1,
6: 1,
7: 1,
8: 1,
9: 2,
10: 1,
11: 1,
12: 1,
13: 2,
14: 1,
15: 1,
16: 1,
17: 1,
18: 1,
19: 1,
20: 1,
21: 1,
22: 1,
23: 1,
24: 1,
25: 1,
26: 1,
27: 1,
28: 1,
29: 1,
30: 1,
31: 1,
32: 3,
33: 4,
34: 5,
35: 6,
36: 7,
37: 8,
38: 9,
39: 10,
40: 11,
41: 12,
42: 13,
43: 14,
44: 15,
45: 16,
46: 17,
47: 18,
48: 19,
49: 20,
50: 21,
51: 22,
52: 23,
53: 24,
54: 25,
55: 26,
56: 27,
57: 28,
58: 29,
59: 30,
60: 31,
61: 32,
62: 33,
63: 34,
64: 35,
65: 36,
66: 37,
67: 38,
68: 39,
69: 40,
70: 41,
71: 42,
72: 43,
73: 44,
74: 45,
75: 46,
76: 47,
77: 48,
78: 49,
79: 50,
80: 51,
81: 52,
82: 53,
83: 54,
84: 55,
85: 56,
86: 57,
87: 58,
88: 59,
89: 60,
90: 61,
91: 62,
92: 63,
93: 64,
94: 65,
95: 66,
96: 67,
97: 68,
98: 69,
99: 70,
100: 71,
101: 72,
102: 73,
103: 74,
104: 75,
105: 76,
106: 77,
107: 78,
108: 79,
109: 80,
110: 81,
111: 82,
112: 83,
113: 84,
114: 85,
115: 86,
116: 87,
117: 88,
118: 89,
119: 90,
120: 91,
121: 92,
122: 93,
123: 94,
124: 95,
125: 96,
126: 97,
160: 172,
161: 163,
162: 132,
163: 133,
164: 189,
165: 150,
166: 232,
167: 134,
168: 142,
169: 139,
170: 157,
171: 169,
172: 164,
174: 138,
175: 218,
176: 131,
177: 147,
178: 242,
179: 243,
180: 141,
181: 151,
182: 136,
184: 222,
185: 241,
186: 158,
187: 170,
188: 245,
189: 244,
190: 246,
191: 162,
192: 173,
193: 201,
194: 199,
195: 174,
196: 98,
197: 99,
198: 144,
199: 100,
200: 203,
201: 101,
202: 200,
203: 202,
204: 207,
205: 204,
206: 205,
207: 206,
208: 233,
209: 102,
210: 211,
211: 208,
212: 209,
213: 175,
214: 103,
215: 240,
216: 145,
217: 214,
218: 212,
219: 213,
220: 104,
221: 235,
222: 237,
223: 137,
224: 106,
225: 105,
226: 107,
227: 109,
228: 108,
229: 110,
230: 160,
231: 111,
232: 113,
233: 112,
234: 114,
235: 115,
236: 117,
237: 116,
238: 118,
239: 119,
240: 234,
241: 120,
242: 122,
243: 121,
244: 123,
245: 125,
246: 124,
247: 184,
248: 161,
249: 127,
250: 126,
251: 128,
252: 129,
253: 236,
254: 238,
255: 186,
262: 253,
263: 254,
268: 255,
269: 256,
273: 257,
286: 248,
287: 249,
304: 250,
305: 215,
321: 226,
322: 227,
338: 176,
339: 177,
350: 251,
351: 252,
352: 228,
353: 229,
376: 187,
381: 230,
382: 231,
402: 166,
710: 216,
711: 225,
728: 219,
729: 220,
730: 221,
731: 224,
733: 223,
960: 155,
8211: 178,
8212: 179,
8216: 182,
8217: 183,
8218: 196,
8220: 180,
8221: 181,
8222: 197,
8224: 130,
8225: 194,
8226: 135,
8230: 171,
8240: 198,
8249: 190,
8250: 191,
8355: 247,
8482: 140,
8486: 159,
8706: 152,
8710: 168,
8719: 154,
8721: 153,
8722: 239,
8725: 188,
8729: 195,
8730: 165,
8734: 146,
8747: 156,
8776: 167,
8800: 143,
8804: 148,
8805: 149,
9674: 185,
61441: 192,
61442: 193,
64257: 192,
64258: 193,
65535: 0 // 0xFFFF指向.notdef
};

View File

@ -0,0 +1,21 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
/**
* @file 字体粗细度量
* @author mengke01(kekee000@gmail.com)
*/
var _default = exports.default = {
100: 'Ultra-light',
200: 'Extra-light',
300: 'Light',
400: 'Semi-light',
500: 'Medium (normal)',
600: 'Semi-bold',
700: 'Bold',
800: 'Extra-Bold',
900: 'Ultra-bold'
};

View File

@ -0,0 +1,21 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
/**
* @file 字体宽度度量
* @author mengke01(kekee000@gmail.com)
*/
var _default = exports.default = {
1: 'Ultra-condensed',
2: 'Extra-condensed',
3: 'Condensed',
4: 'Semi-condensed',
5: 'Medium (normal)',
6: 'Semi-expanded',
7: 'Expanded',
8: 'Extra-expanded',
9: 'Ultra-expanded'
};

View File

@ -0,0 +1,22 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = eot2base64;
var _bytes2base = _interopRequireDefault(require("./util/bytes2base64"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file eot数组转base64编码
* @author mengke01(kekee000@gmail.com)
*/
/**
* eot数组转base64编码
*
* @param {Array} arrayBuffer ArrayBuffer对象
* @return {string} base64编码
*/
function eot2base64(arrayBuffer) {
return 'data:font/eot;charset=utf-8;base64,' + (0, _bytes2base.default)(arrayBuffer);
}

View File

@ -0,0 +1,80 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = eot2ttf;
var _reader = _interopRequireDefault(require("./reader"));
var _writer = _interopRequireDefault(require("./writer"));
var _error = _interopRequireDefault(require("./error"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file eot转ttf
* @author mengke01(kekee000@gmail.com)
*/
/**
* eot格式转换成ttf字体格式
*
* @param {ArrayBuffer} eotBuffer eot缓冲数组
* @param {Object} options 选项
*
* @return {ArrayBuffer} ttf格式byte流
*/
// eslint-disable-next-line no-unused-vars
function eot2ttf(eotBuffer) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
// 这里用小尾方式读取
var eotReader = new _reader.default(eotBuffer, 0, eotBuffer.byteLength, true);
// check magic number
var magicNumber = eotReader.readUint16(34);
if (magicNumber !== 0x504C) {
_error.default.raise(10110);
}
// check version
var version = eotReader.readUint32(8);
if (version !== 0x20001 && version !== 0x10000 && version !== 0x20002) {
_error.default.raise(10110);
}
var eotSize = eotBuffer.byteLength || eotBuffer.length;
var fontSize = eotReader.readUint32(4);
var fontOffset = 82;
var familyNameSize = eotReader.readUint16(fontOffset);
fontOffset += 4 + familyNameSize;
var styleNameSize = eotReader.readUint16(fontOffset);
fontOffset += 4 + styleNameSize;
var versionNameSize = eotReader.readUint16(fontOffset);
fontOffset += 4 + versionNameSize;
var fullNameSize = eotReader.readUint16(fontOffset);
fontOffset += 2 + fullNameSize;
// version 0x20001
if (version === 0x20001 || version === 0x20002) {
var rootStringSize = eotReader.readUint16(fontOffset + 2);
fontOffset += 4 + rootStringSize;
}
// version 0x20002
if (version === 0x20002) {
fontOffset += 10;
var signatureSize = eotReader.readUint16(fontOffset);
fontOffset += 2 + signatureSize;
fontOffset += 4;
var eudcFontSize = eotReader.readUint32(fontOffset);
fontOffset += 4 + eudcFontSize;
}
if (fontOffset + fontSize > eotSize) {
_error.default.raise(10001);
}
// support slice
if (eotBuffer.slice) {
return eotBuffer.slice(fontOffset, fontOffset + fontSize);
}
// not support ArrayBuffer.slice eg. IE10
var bytes = eotReader.readBytes(fontOffset, fontSize);
return new _writer.default(new ArrayBuffer(fontSize)).writeBytes(bytes).getBuffer();
}

52
vendor/fonteditor-core/lib/ttf/error.js vendored Normal file
View File

@ -0,0 +1,52 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _string = _interopRequireDefault(require("../common/string"));
var _i18n = _interopRequireDefault(require("./i18n"));
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); } /**
* @file ttf 相关错误号定义
* @author mengke01(kekee000@gmail.com)
*/
var _default = exports.default = {
/**
* 抛出一个异常
*
* @param {Object} e 异常号或者异常对象
* @param {...Array} fargs args 参数
*
* 例如
* e = 1001
* e = {
* number: 1001,
* data: 错误数据
* }
*/
raise: function raise(e) {
var number;
var data;
if (_typeof(e) === 'object') {
number = e.number || 0;
data = e.data;
} else {
number = e;
}
var message = _i18n.default.lang[number];
for (var _len = arguments.length, fargs = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
fargs[_key - 1] = arguments[_key];
}
if (fargs.length > 0) {
var args = _typeof(fargs[0]) === 'object' ? fargs[0] : fargs;
message = _string.default.format(message, args);
}
var event = new Error(message);
event.number = number;
if (data) {
event.data = data;
}
throw event;
}
};

381
vendor/fonteditor-core/lib/ttf/font.js vendored Normal file
View File

@ -0,0 +1,381 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Font = void 0;
exports.createFont = createFont;
exports.default = void 0;
var _buffer = _interopRequireDefault(require("../nodejs/buffer"));
var _getEmptyttfObject = _interopRequireDefault(require("./getEmptyttfObject"));
var _ttf = _interopRequireDefault(require("./ttf"));
var _woff2ttf = _interopRequireDefault(require("./woff2ttf"));
var _otf2ttfobject = _interopRequireDefault(require("./otf2ttfobject"));
var _eot2ttf = _interopRequireDefault(require("./eot2ttf"));
var _svg2ttfobject = _interopRequireDefault(require("./svg2ttfobject"));
var _ttfreader = _interopRequireDefault(require("./ttfreader"));
var _ttfwriter = _interopRequireDefault(require("./ttfwriter"));
var _ttf2eot = _interopRequireDefault(require("./ttf2eot"));
var _ttf2woff = _interopRequireDefault(require("./ttf2woff"));
var _ttf2svg = _interopRequireDefault(require("./ttf2svg"));
var _ttf2symbol = _interopRequireDefault(require("./ttf2symbol"));
var _ttftowoff = _interopRequireDefault(require("./ttftowoff2"));
var _woff2tottf = _interopRequireDefault(require("./woff2tottf"));
var _ttf2base = _interopRequireDefault(require("./ttf2base64"));
var _eot2base = _interopRequireDefault(require("./eot2base64"));
var _woff2base = _interopRequireDefault(require("./woff2base64"));
var _svg2base = _interopRequireDefault(require("./svg2base64"));
var _bytes2base = _interopRequireDefault(require("./util/bytes2base64"));
var _woff2tobase = _interopRequireDefault(require("./woff2tobase64"));
var _optimizettf = _interopRequireDefault(require("./util/optimizettf"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
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); }
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); } /**
* @file 字体管理对象处理字体相关的读取查询转换
*
* @author mengke01(kekee000@gmail.com)
*/
// 必须是nodejs环境下的Buffer对象才能触发buffer转换
var SUPPORT_BUFFER = (typeof process === "undefined" ? "undefined" : _typeof(process)) === 'object' && _typeof(process.versions) === 'object' && typeof process.versions.node !== 'undefined' && typeof Buffer === 'function';
var Font = exports.Font = /*#__PURE__*/function () {
/**
* 字体对象构造函数
*
* @param {ArrayBuffer|Buffer|string|Document} buffer 字体数据
* @param {Object} options 读取参数
*/
function Font(buffer) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
type: 'ttf'
};
_classCallCheck(this, Font);
// 字形对象
if (_typeof(buffer) === 'object' && buffer.glyf) {
this.set(buffer);
}
// buffer
else if (buffer) {
this.read(buffer, options);
}
// 空
else {
this.readEmpty();
}
}
/**
* Create a Font instance
*
* @param {ArrayBuffer|Buffer|string|Document} buffer 字体数据
* @param {Object} options 读取参数
* @return {Font}
*/
return _createClass(Font, [{
key: "readEmpty",
value:
/**
* 设置一个空的 ttfObject 对象
*
* @return {Font}
*/
function readEmpty() {
this.data = (0, _getEmptyttfObject.default)();
return this;
}
/**
* 读取字体数据
*
* @param {ArrayBuffer|Buffer|string|Document} buffer 字体数据
* @param {Object} options 读取参数
* @param {string} options.type 字体类型
*
* ttf, woff , eot 读取配置
* @param {boolean} options.hinting 是否保留 hinting 信息
* @param {boolean} options.kerning 是否保留 kerning 信息
* @param {boolean} options.compound2simple 复合字形转简单字形
*
* woff 读取配置
* @param {Function} options.inflate 解压相关函数
*
* svg 读取配置
* @param {boolean} options.combinePath 是否合并成单个字形仅限于普通svg导入
* @return {Font}
*/
}, {
key: "read",
value: function read(buffer, options) {
// nodejs buffer
if (SUPPORT_BUFFER) {
if (buffer instanceof Buffer) {
buffer = _buffer.default.toArrayBuffer(buffer);
}
}
if (options.type === 'ttf') {
this.data = new _ttfreader.default(options).read(buffer);
} else if (options.type === 'otf') {
this.data = (0, _otf2ttfobject.default)(buffer, options);
} else if (options.type === 'eot') {
buffer = (0, _eot2ttf.default)(buffer, options);
this.data = new _ttfreader.default(options).read(buffer);
} else if (options.type === 'woff') {
buffer = (0, _woff2ttf.default)(buffer, options);
this.data = new _ttfreader.default(options).read(buffer);
} else if (options.type === 'woff2') {
buffer = (0, _woff2tottf.default)(buffer, options);
this.data = new _ttfreader.default(options).read(buffer);
} else if (options.type === 'svg') {
this.data = (0, _svg2ttfobject.default)(buffer, options);
} else {
throw new Error('not support font type' + options.type);
}
this.type = options.type;
return this;
}
/**
* 写入字体数据
*
* @param {Object} options 写入参数
* @param {string} options.type 字体类型, 默认 ttf
* @param {boolean} options.toBuffer nodejs 环境中返回 Buffer 对象, 默认 true
*
* ttf 字体参数
* @param {boolean} options.hinting 是否保留 hinting 信息
* @param {boolean} options.kerning 是否保留 kerning 信息
* svg,woff 字体参数
* @param {Object} options.metadata 字体相关的信息
*
* woff 字体参数
* @param {Function} options.deflate 压缩相关函数
* @return {Buffer|ArrayBuffer|string}
*/
}, {
key: "write",
value: function write() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
if (!options.type) {
options.type = this.type;
}
var buffer = null;
if (options.type === 'ttf') {
buffer = new _ttfwriter.default(options).write(this.data);
} else if (options.type === 'eot') {
buffer = new _ttfwriter.default(options).write(this.data);
buffer = (0, _ttf2eot.default)(buffer, options);
} else if (options.type === 'woff') {
buffer = new _ttfwriter.default(options).write(this.data);
buffer = (0, _ttf2woff.default)(buffer, options);
} else if (options.type === 'woff2') {
buffer = new _ttfwriter.default(options).write(this.data);
buffer = (0, _ttftowoff.default)(buffer, options);
} else if (options.type === 'svg') {
buffer = (0, _ttf2svg.default)(this.data, options);
} else if (options.type === 'symbol') {
buffer = (0, _ttf2symbol.default)(this.data, options);
} else {
throw new Error('not support font type' + options.type);
}
if (SUPPORT_BUFFER) {
if (false !== options.toBuffer && buffer instanceof ArrayBuffer) {
buffer = _buffer.default.toBuffer(buffer);
}
}
return buffer;
}
/**
* 转换成 base64编码
*
* @param {Object} options 写入参数
* @param {string} options.type 字体类型, 默认 ttf
* 其他 options参数, 参考 write
* @see write
*
* @param {ArrayBuffer=} buffer 如果提供了buffer数据则使用 buffer数据, 否则转换现有的 font
* @return {string}
*/
}, {
key: "toBase64",
value: function toBase64(options, buffer) {
if (!options.type) {
options.type = this.type;
}
if (buffer) {
if (SUPPORT_BUFFER) {
if (buffer instanceof Buffer) {
buffer = _buffer.default.toArrayBuffer(buffer);
}
}
} else {
options.toBuffer = false;
buffer = this.write(options);
}
var base64Str;
if (options.type === 'ttf') {
base64Str = (0, _ttf2base.default)(buffer);
} else if (options.type === 'eot') {
base64Str = (0, _eot2base.default)(buffer);
} else if (options.type === 'woff') {
base64Str = (0, _woff2base.default)(buffer);
} else if (options.type === 'woff2') {
base64Str = (0, _woff2tobase.default)(buffer);
} else if (options.type === 'svg') {
base64Str = (0, _svg2base.default)(buffer);
} else if (options.type === 'symbol') {
base64Str = (0, _svg2base.default)(buffer, 'image/svg+xml');
} else {
throw new Error('not support font type' + options.type);
}
return base64Str;
}
/**
* 设置 font 对象
*
* @param {Object} data font的ttfObject对象
* @return {this}
*/
}, {
key: "set",
value: function set(data) {
this.data = data;
return this;
}
/**
* 获取 font 数据
*
* @return {Object} ttfObject 对象
*/
}, {
key: "get",
value: function get() {
return this.data;
}
/**
* 对字形数据进行优化
*
* @param {Object} out 输出结果
* @param {boolean|Object} out.result `true` 或者有问题的地方
* @return {Font}
*/
}, {
key: "optimize",
value: function optimize(out) {
var result = (0, _optimizettf.default)(this.data);
if (out) {
out.result = result;
}
return this;
}
/**
* 将字体中的复合字形转为简单字形
*
* @return {this}
*/
}, {
key: "compound2simple",
value: function compound2simple() {
var ttfHelper = this.getHelper();
ttfHelper.compound2simple();
this.data = ttfHelper.get();
return this;
}
/**
* 对字形按照unicode编码排序
*
* @return {this}
*/
}, {
key: "sort",
value: function sort() {
var ttfHelper = this.getHelper();
ttfHelper.sortGlyf();
this.data = ttfHelper.get();
return this;
}
/**
* 查找相关字形
*
* @param {Object} condition 查询条件
* @param {Array|number} condition.unicode unicode编码列表或者单个unicode编码
* @param {string} condition.name glyf名字例如`uniE001`, `uniE`
* @param {Function} condition.filter 自定义过滤器
* @example
* condition.filter(glyf) {
* return glyf.name === 'logo';
* }
* @return {Array} glyf字形列表
*/
}, {
key: "find",
value: function find(condition) {
var ttfHelper = this.getHelper();
var indexList = ttfHelper.findGlyf(condition);
return indexList.length ? ttfHelper.getGlyf(indexList) : indexList;
}
/**
* 合并 font 到当前的 font
*
* @param {Object} font Font 对象
* @param {Object} options 参数选项
* @param {boolean} options.scale 是否自动缩放
* @param {boolean} options.adjustGlyf 是否调整字形以适应边界
* ( options.scale 参数互斥)
*
* @return {Font}
*/
}, {
key: "merge",
value: function merge(font, options) {
var ttfHelper = this.getHelper();
ttfHelper.mergeGlyf(font.get(), options);
this.data = ttfHelper.get();
return this;
}
/**
* 获取 TTF helper 实例
*/
}, {
key: "getHelper",
value: function getHelper() {
return new _ttf.default(this.data);
}
}], [{
key: "create",
value: function create(buffer, options) {
return new Font(buffer, options);
}
}]);
}();
/**
* base64序列化buffer 数据
*
* @param {ArrayBuffer|Buffer|string} buffer 字体数据
* @return {Font}
*/
Font.toBase64 = function (buffer) {
if (typeof buffer === 'string') {
// node 环境中没有 btoa 函数
if (typeof btoa === 'undefined') {
return Buffer.from(buffer, 'binary').toString('base64');
}
return btoa(buffer);
}
return (0, _bytes2base.default)(buffer);
};
function createFont(buffer, options) {
return new Font(buffer, options);
}
var _default = exports.default = Font;

View File

@ -0,0 +1,21 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = getEmpty;
var _lang = require("../common/lang");
var _empty = _interopRequireDefault(require("./data/empty"));
var _default = _interopRequireDefault(require("./data/default"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file 获取空的ttf对象
* @author mengke01(kekee000@gmail.com)
*/
function getEmpty() {
var ttf = (0, _lang.clone)(_empty.default);
Object.assign(ttf.name, _default.default.name);
ttf.head.created = ttf.head.modified = Date.now();
return ttf;
}

70
vendor/fonteditor-core/lib/ttf/i18n.js vendored Normal file
View File

@ -0,0 +1,70 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _I18n = _interopRequireDefault(require("../common/I18n"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file 语言字符串管理
* @author mengke01(kekee000@gmail.com)
*/
var zh = {
// error define
10001: '超出读取范围:${0}, ${1}',
10002: '超出写入范围:${0}, ${1}',
10003: '未知数据类型:${0}, ${1}',
10004: '不支持svg解析',
10101: '错误的ttf文件',
10102: '错误的woff文件',
10103: '错误的svg文件',
10104: '读取ttf文件错误',
10105: '读取woff文件错误',
10106: '读取svg文件错误',
10107: '写入ttf文件错误',
10108: '写入woff文件错误',
10109: '写入svg文件错误',
10112: '写入svg symbol 错误',
10110: '读取eot文件错误',
10111: '读取eot字体错误',
10200: '重复的unicode代码点字形序号${0}',
10201: 'ttf字形轮廓数据为空',
10202: '不支持标志位ARGS_ARE_XY_VALUES',
10203: '未找到表:${0}',
10204: '读取ttf表错误',
10205: '未找到解压函数',
10301: '错误的otf文件',
10302: '读取otf表错误',
10303: 'otf字形轮廓数据为空'
};
var en = {
// error define
10001: 'Reading index out of range: ${0}, ${1}',
10002: 'Writing index out of range: ${0}, ${1}',
10003: 'Unknown datatype: ${0}, ${1}',
10004: 'No svg parser',
10101: 'ttf file damaged',
10102: 'woff file damaged',
10103: 'svg file damaged',
10104: 'Read ttf error',
10105: 'Read woff error',
10106: 'Read svg error',
10107: 'Write ttf error',
10108: 'Write woff error',
10109: 'Write svg error',
10112: 'Write svg symbol error',
10110: 'Read eot error',
10111: 'Write eot error',
10200: 'Repeat unicode, glyph index: ${0}',
10201: 'ttf `glyph` data is empty',
10202: 'Not support compound glyph flag: ARGS_ARE_XY_VALUES',
10203: 'No ttf table: ${0}',
10204: 'Read ttf table data error',
10205: 'No zip deflate function',
10301: 'otf file damaged',
10302: 'Read otf table error',
10303: 'otf `glyph` data is empty'
};
var _default = exports.default = new _I18n.default([['zh-cn', zh], ['en-us', en]], typeof window !== 'undefined' ? window.language : 'en-us');

View File

@ -0,0 +1,22 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = ttf2base64;
var _bytes2base = _interopRequireDefault(require("./util/bytes2base64"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file otf转bse64字体
* @author mengke01(kekee000@gmail.com)
*/
/**
* ttf 二进制转base64编码
*
* @param {Array} arrayBuffer ArrayBuffer对象
* @return {string} base64编码
*/
function ttf2base64(arrayBuffer) {
return 'data:font/otf;charset=utf-8;base64,' + (0, _bytes2base.default)(arrayBuffer);
}

View File

@ -0,0 +1,66 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = otf2ttfobject;
var _error = _interopRequireDefault(require("./error"));
var _otfreader = _interopRequireDefault(require("./otfreader"));
var _otfContours2ttfContours = _interopRequireDefault(require("./util/otfContours2ttfContours"));
var _computeBoundingBox = require("../graphics/computeBoundingBox");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } /**
* @file otf格式转ttf格式对象
* @author mengke01(kekee000@gmail.com)
*/
/**
* otf格式转ttf格式对象
*
* @param {ArrayBuffer|otfObject} otfBuffer 原始数据或者解析后的otf数据
* @param {Object} options 参数
* @return {Object} ttfObject对象
*/
function otf2ttfobject(otfBuffer, options) {
var otfObject;
if (otfBuffer instanceof ArrayBuffer) {
var otfReader = new _otfreader.default(options);
otfObject = otfReader.read(otfBuffer);
otfReader.dispose();
} else if (otfBuffer.head && otfBuffer.glyf && otfBuffer.cmap) {
otfObject = otfBuffer;
} else {
_error.default.raise(10111);
}
// 转换otf轮廓
otfObject.glyf.forEach(function (g) {
g.contours = (0, _otfContours2ttfContours.default)(g.contours);
var box = _computeBoundingBox.computePathBox.apply(void 0, _toConsumableArray(g.contours));
if (box) {
g.xMin = box.x;
g.xMax = box.x + box.width;
g.yMin = box.y;
g.yMax = box.y + box.height;
g.leftSideBearing = g.xMin;
} else {
g.xMin = 0;
g.xMax = 0;
g.yMin = 0;
g.yMax = 0;
g.leftSideBearing = 0;
}
});
otfObject.version = 0x1;
// 修改maxp相关配置
otfObject.maxp.version = 1.0;
otfObject.maxp.maxZones = otfObject.maxp.maxTwilightPoints ? 2 : 1;
delete otfObject.CFF;
delete otfObject.VORG;
return otfObject;
}

View File

@ -0,0 +1,182 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _directory = _interopRequireDefault(require("./table/directory"));
var _supportOtf = _interopRequireDefault(require("./table/support-otf"));
var _reader = _interopRequireDefault(require("./reader"));
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 otf字体读取
* @author mengke01(kekee000@gmail.com)
*/
var OTFReader = exports.default = /*#__PURE__*/function () {
/**
* OTF读取函数
*
* @param {Object} options 写入参数
* @constructor
*/
function OTFReader() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
_classCallCheck(this, OTFReader);
options.subset = options.subset || [];
this.options = options;
}
/**
* 初始化
*
* @param {ArrayBuffer} buffer buffer对象
* @return {Object} ttf对象
*/
return _createClass(OTFReader, [{
key: "readBuffer",
value: function readBuffer(buffer) {
var reader = new _reader.default(buffer, 0, buffer.byteLength, false);
var font = {};
// version
font.version = reader.readString(0, 4);
if (font.version !== 'OTTO') {
_error.default.raise(10301);
}
// num tables
font.numTables = reader.readUint16();
if (font.numTables <= 0 || font.numTables > 100) {
_error.default.raise(10302);
}
// searchRange
font.searchRange = reader.readUint16();
// entrySelector
font.entrySelector = reader.readUint16();
// rangeShift
font.rangeShift = reader.readUint16();
font.tables = new _directory.default(reader.offset).read(reader, font);
if (!font.tables.head || !font.tables.cmap || !font.tables.CFF) {
_error.default.raise(10302);
}
font.readOptions = this.options;
// 读取支持的表数据
Object.keys(_supportOtf.default).forEach(function (tableName) {
if (font.tables[tableName]) {
var offset = font.tables[tableName].offset;
font[tableName] = new _supportOtf.default[tableName](offset).read(reader, font);
}
});
if (!font.CFF.glyf) {
_error.default.raise(10303);
}
reader.dispose();
return font;
}
/**
* 关联glyf相关的信息
*
* @param {Object} font font对象
*/
}, {
key: "resolveGlyf",
value: function resolveGlyf(font) {
var codes = font.cmap;
var glyf = font.CFF.glyf;
var subsetMap = font.readOptions.subset ? font.subsetMap : null; // 当前ttf的子集列表
// unicode
Object.keys(codes).forEach(function (c) {
var i = codes[c];
if (subsetMap && !subsetMap[i]) {
return;
}
if (!glyf[i].unicode) {
glyf[i].unicode = [];
}
glyf[i].unicode.push(+c);
});
// leftSideBearing
font.hmtx.forEach(function (item, i) {
if (subsetMap && !subsetMap[i]) {
return;
}
glyf[i].advanceWidth = glyf[i].advanceWidth || item.advanceWidth || 0;
glyf[i].leftSideBearing = item.leftSideBearing;
});
// 设置了subsetMap之后需要选取subset中的字形
if (subsetMap) {
var subGlyf = [];
Object.keys(subsetMap).forEach(function (i) {
subGlyf.push(glyf[+i]);
});
glyf = subGlyf;
}
font.glyf = glyf;
}
/**
* 清除非必须的表
*
* @param {Object} font font对象
*/
}, {
key: "cleanTables",
value: function cleanTables(font) {
delete font.readOptions;
delete font.tables;
delete font.hmtx;
delete font.post.glyphNameIndex;
delete font.post.names;
delete font.subsetMap;
// 删除无用的表
var cff = font.CFF;
delete cff.glyf;
delete cff.charset;
delete cff.encoding;
delete cff.gsubrs;
delete cff.gsubrsBias;
delete cff.subrs;
delete cff.subrsBias;
}
/**
* 获取解析后的ttf文档
*
* @param {ArrayBuffer} buffer buffer对象
*
* @return {Object} ttf文档
*/
}, {
key: "read",
value: function read(buffer) {
this.font = this.readBuffer(buffer);
this.resolveGlyf(this.font);
this.cleanTables(this.font);
return this.font;
}
/**
* 注销
*/
}, {
key: "dispose",
value: function dispose() {
delete this.font;
delete this.options;
}
}]);
}();

249
vendor/fonteditor-core/lib/ttf/reader.js vendored Normal file
View File

@ -0,0 +1,249 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _lang = require("../common/lang");
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 _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
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 数据读取器
* @author mengke01(kekee000@gmail.com)
*
* thanks to
* ynakajima/ttf.js
* https://github.com/ynakajima/ttf.js
*/
// 检查数组支持情况
if (typeof ArrayBuffer === 'undefined' || typeof DataView === 'undefined') {
throw new Error('not support ArrayBuffer and DataView');
}
// 数据类型
var dataType = {
Int8: 1,
Int16: 2,
Int32: 4,
Uint8: 1,
Uint16: 2,
Uint32: 4,
Float32: 4,
Float64: 8
};
var Reader = exports.default = /*#__PURE__*/function () {
/**
* 读取器
*
* @constructor
* @param {Array.<byte>} buffer 缓冲数组
* @param {number} offset 起始偏移
* @param {number} length 数组长度
* @param {boolean} littleEndian 是否小尾
*/
function Reader(buffer, offset, length, littleEndian) {
_classCallCheck(this, Reader);
var bufferLength = buffer.byteLength || buffer.length;
this.offset = offset || 0;
this.length = length || bufferLength - this.offset;
this.littleEndian = littleEndian || false;
this.view = new DataView(buffer, this.offset, this.length);
}
/**
* 读取指定的数据类型
*
* @param {string} type 数据类型
* @param {number=} offset 位移
* @param {boolean=} littleEndian 是否小尾
* @return {number} 返回值
*/
return _createClass(Reader, [{
key: "read",
value: function read(type, offset, littleEndian) {
// 使用当前位移
if (undefined === offset) {
offset = this.offset;
}
// 使用小尾
if (undefined === littleEndian) {
littleEndian = this.littleEndian;
}
// 扩展方法
if (undefined === dataType[type]) {
return this['read' + type](offset, littleEndian);
}
var size = dataType[type];
this.offset = offset + size;
return this.view['get' + type](offset, littleEndian);
}
/**
* 获取指定的字节数组
*
* @param {number} offset 偏移
* @param {number} length 字节长度
* @return {Array} 字节数组
*/
}, {
key: "readBytes",
value: function readBytes(offset) {
var length = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
if (length == null) {
length = offset;
offset = this.offset;
}
if (length < 0 || offset + length > this.length) {
_error.default.raise(10001, this.length, offset + length);
}
var buffer = [];
for (var i = 0; i < length; ++i) {
buffer.push(this.view.getUint8(offset + i));
}
this.offset = offset + length;
return buffer;
}
/**
* 读取一个string
*
* @param {number} offset 偏移
* @param {number} length 长度
* @return {string} 字符串
*/
}, {
key: "readString",
value: function readString(offset) {
var length = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
if (length == null) {
length = offset;
offset = this.offset;
}
if (length < 0 || offset + length > this.length) {
_error.default.raise(10001, this.length, offset + length);
}
var value = '';
for (var i = 0; i < length; ++i) {
var c = this.readUint8(offset + i);
value += String.fromCharCode(c);
}
this.offset = offset + length;
return value;
}
/**
* 读取一个字符
*
* @param {number} offset 偏移
* @return {string} 字符串
*/
}, {
key: "readChar",
value: function readChar(offset) {
return this.readString(offset, 1);
}
/**
* 读取一个uint24整形
*
* @param {number} offset 偏移
* @return {number}
*/
}, {
key: "readUint24",
value: function readUint24(offset) {
var _this$readBytes = this.readBytes(offset || this.offset, 3),
_this$readBytes2 = _slicedToArray(_this$readBytes, 3),
i = _this$readBytes2[0],
j = _this$readBytes2[1],
k = _this$readBytes2[2];
return (i << 16) + (j << 8) + k;
}
/**
* 读取fixed类型
*
* @param {number} offset 偏移
* @return {number} float
*/
}, {
key: "readFixed",
value: function readFixed(offset) {
if (undefined === offset) {
offset = this.offset;
}
var val = this.readInt32(offset, false) / 65536.0;
return Math.ceil(val * 100000) / 100000;
}
/**
* 读取长日期
*
* @param {number} offset 偏移
* @return {Date} Date对象
*/
}, {
key: "readLongDateTime",
value: function readLongDateTime(offset) {
if (undefined === offset) {
offset = this.offset;
}
// new Date(1970, 1, 1).getTime() - new Date(1904, 1, 1).getTime();
var delta = -2077545600000;
var time = this.readUint32(offset + 4, false);
var date = new Date();
date.setTime(time * 1000 + delta);
return date;
}
/**
* 跳转到指定偏移
*
* @param {number} offset 偏移
* @return {Object} this
*/
}, {
key: "seek",
value: function seek(offset) {
if (undefined === offset) {
this.offset = 0;
}
if (offset < 0 || offset > this.length) {
_error.default.raise(10001, this.length, offset);
}
this.offset = offset;
return this;
}
/**
* 注销
*/
}, {
key: "dispose",
value: function dispose() {
delete this.view;
}
}]);
}(); // 直接支持的数据类型 — 直接绑定,避免 curry 闭包开销
Object.keys(dataType).forEach(function (type) {
var size = dataType[type];
Reader.prototype['read' + type] = function (offset) {
if (offset === undefined) offset = this.offset;
this.offset = offset + size;
return this.view['get' + type](offset, this.littleEndian);
};
});

View File

@ -0,0 +1,66 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = contoursTransform;
var _matrix = require("../../graphics/matrix");
var _pathTransform = _interopRequireDefault(require("../../graphics/pathTransform"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file 根据transform参数变换轮廓
* @author mengke01(kekee000@gmail.com)
*/
/**
* 根据transform参数变换轮廓
*
* @param {Array} contours 轮廓集合
* @param {Array} transforms 变换指令集合
* transforms = [{
* name: 'scale'
* params: [3,4]
* }]
*
* @return {Array} 变换后的轮廓数组
*/
function contoursTransform(contours, transforms) {
if (!contours || !contours.length || !transforms || !transforms.length) {
return contours;
}
var matrix = [1, 0, 0, 1, 0, 0];
for (var i = 0, l = transforms.length; i < l; i++) {
var transform = transforms[i];
var params = transform.params;
var radian = null;
switch (transform.name) {
case 'translate':
matrix = (0, _matrix.mul)(matrix, [1, 0, 0, 1, params[0], params[1]]);
break;
case 'scale':
matrix = (0, _matrix.mul)(matrix, [params[0], 0, 0, params[1], 0, 0]);
break;
case 'matrix':
matrix = (0, _matrix.mul)(matrix, [params[0], params[1], params[2], params[3], params[4], params[5]]);
break;
case 'rotate':
radian = params[0] * Math.PI / 180;
if (params.length > 1) {
matrix = (0, _matrix.multiply)(matrix, [1, 0, 0, 1, -params[1], -params[2]], [Math.cos(radian), Math.sin(radian), -Math.sin(radian), Math.cos(radian), 0, 0], [1, 0, 0, 1, params[1], params[2]]);
} else {
matrix = (0, _matrix.mul)(matrix, [Math.cos(radian), Math.sin(radian), -Math.sin(radian), Math.cos(radian), 0, 0]);
}
break;
case 'skewX':
matrix = (0, _matrix.mul)(matrix, [1, 0, Math.tan(params[0] * Math.PI / 180), 1, 0, 0]);
break;
case 'skewY':
matrix = (0, _matrix.mul)(matrix, [1, Math.tan(params[0] * Math.PI / 180), 0, 1, 0, 0]);
break;
}
}
contours.forEach(function (p) {
(0, _pathTransform.default)(p, matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);
});
return contours;
}

View File

@ -0,0 +1,39 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = oval2contour;
var _computeBoundingBox = require("../../graphics/computeBoundingBox");
var _pathAdjust = _interopRequireDefault(require("../../graphics/pathAdjust"));
var _circle = _interopRequireDefault(require("../../graphics/path/circle"));
var _lang = require("../../common/lang");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file 椭圆转换成轮廓
* @author mengke01(kekee000@gmail.com)
*/
/**
* 椭圆转换成轮廓
*
* @param {number} cx 椭圆中心点x
* @param {number} cy 椭圆中心点y
* @param {number} rx 椭圆x轴半径
* @param {number} ry 椭圆y周半径
* @return {Array} 轮廓数组
*/
function oval2contour(cx, cy, rx, ry) {
if (undefined === ry) {
ry = rx;
}
var bound = (0, _computeBoundingBox.computePath)(_circle.default);
var scaleX = +rx * 2 / bound.width;
var scaleY = +ry * 2 / bound.height;
var centerX = bound.width * scaleX / 2;
var centerY = bound.height * scaleY / 2;
var contour = (0, _lang.clone)(_circle.default);
(0, _pathAdjust.default)(contour, scaleX, scaleY);
(0, _pathAdjust.default)(contour, 1, 1, +cx - centerX, +cy - centerY);
return contour;
}

View File

@ -0,0 +1,36 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = _default;
/**
* @file 解析参数数组
* @author mengke01(kekee000@gmail.com)
*/
var SEGMENT_REGEX = /-?\d+(?:\.\d+)?(?:e[-+]?\d+)?\b/g;
/**
* 获取参数值
*
* @param {string} d 参数
* @return {number} 参数值
*/
function getSegment(d) {
return +d.trim();
}
/**
* 解析参数数组
*
* @param {string} str 参数字符串
* @return {Array} 参数数组
*/
function _default(str) {
if (!str) {
return [];
}
var matchs = str.match(SEGMENT_REGEX);
return matchs ? matchs.map(getSegment) : [];
}

View File

@ -0,0 +1,42 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = parseTransform;
var _parseParams = _interopRequireDefault(require("./parseParams"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file 解析transform参数
* @author mengke01(kekee000@gmail.com)
*/
var TRANSFORM_REGEX = /(\w+)\s*\(([\d-.,\s]*)\)/g;
/**
* 解析transform参数
*
* @param {string} str 参数字符串
* @return {Array} transform数组, 格式如下
* [
* {
* name: 'scale',
* params: []
* }
* ]
*/
function parseTransform(str) {
if (!str) {
return false;
}
TRANSFORM_REGEX.lastIndex = 0;
var transforms = [];
var match;
while (match = TRANSFORM_REGEX.exec(str)) {
transforms.push({
name: match[1],
params: (0, _parseParams.default)(match[2])
});
}
return transforms;
}

View File

@ -0,0 +1,454 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = path2contours;
var _bezierCubic2Q = _interopRequireDefault(require("../../math/bezierCubic2Q2"));
var _getArc = _interopRequireDefault(require("../../graphics/getArc"));
var _parseParams = _interopRequireDefault(require("./parseParams"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file svg path转换为轮廓
* @author mengke01(kekee000@gmail.com)
*/
/**
* 三次贝塞尔曲线转二次贝塞尔曲线
*
* @param {Array} cubicList 三次曲线数组
* @param {Array} contour 当前解析后的轮廓数组
* @return {Array} 当前解析后的轮廓数组
*/
function cubic2Points(cubicList, contour) {
var i;
var l;
var q2List = [];
cubicList.forEach(function (c) {
var list = (0, _bezierCubic2Q.default)(c[0], c[1], c[2], c[3]);
for (i = 0, l = list.length; i < l; i++) {
q2List.push(list[i]);
}
});
var q2;
var prevq2;
for (i = 0, l = q2List.length; i < l; i++) {
q2 = q2List[i];
if (i === 0) {
contour.push({
x: q2[1].x,
y: q2[1].y
});
contour.push({
x: q2[2].x,
y: q2[2].y,
onCurve: true
});
} else {
prevq2 = q2List[i - 1];
// 检查是否存在切线点
if (prevq2[1].x + q2[1].x === 2 * q2[0].x && prevq2[1].y + q2[1].y === 2 * q2[0].y) {
contour.pop();
}
contour.push({
x: q2[1].x,
y: q2[1].y
});
contour.push({
x: q2[2].x,
y: q2[2].y,
onCurve: true
});
}
}
contour.push({
x: q2[2].x,
y: q2[2].y,
onCurve: true
});
return contour;
}
/**
* svg 命令数组转轮廓
*
* @param {Array} segments svg 命令数组
* @return {Array} 轮廓数组
*/
function segments2Contours(segments) {
// 解析segments
var contours = [];
var contour = [];
var prevX = 0;
var prevY = 0;
var segment;
var args;
var cmd;
var relative;
var q;
var ql;
var px;
var py;
var cubicList;
var p1;
var p2;
var c1;
var c2;
var prevCubicC1; // 三次贝塞尔曲线前一个控制点,用于绘制`s`命令
for (var i = 0, l = segments.length; i < l; i++) {
segment = segments[i];
cmd = segment.cmd;
relative = segment.relative;
args = segment.args;
if (args && !args.length && cmd !== 'Z') {
console.warn('`' + cmd + '` command args empty!');
continue;
}
if (cmd === 'Z') {
contours.push(contour);
contour = [];
} else if (cmd === 'M' || cmd === 'L') {
if (args.length % 2) {
throw new Error('`M` command error:' + args.join(','));
}
// 这里可能会连续绘制,最后一个是终点
if (relative) {
px = prevX;
py = prevY;
} else {
px = 0;
py = 0;
}
for (q = 0, ql = args.length; q < ql; q += 2) {
if (relative) {
px += args[q];
py += args[q + 1];
} else {
px = args[q];
py = args[q + 1];
}
contour.push({
x: px,
y: py,
onCurve: true
});
}
prevX = px;
prevY = py;
} else if (cmd === 'H') {
if (relative) {
prevX += args[0];
} else {
prevX = args[0];
}
contour.push({
x: prevX,
y: prevY,
onCurve: true
});
} else if (cmd === 'V') {
if (relative) {
prevY += args[0];
} else {
prevY = args[0];
}
contour.push({
x: prevX,
y: prevY,
onCurve: true
});
}
// 二次贝塞尔
else if (cmd === 'Q') {
// 这里可能会连续绘制,最后一个是终点
if (relative) {
px = prevX;
py = prevY;
} else {
px = 0;
py = 0;
}
for (q = 0, ql = args.length; q < ql; q += 4) {
contour.push({
x: px + args[q],
y: py + args[q + 1]
});
contour.push({
x: px + args[q + 2],
y: py + args[q + 3],
onCurve: true
});
if (relative) {
px += args[q + 2];
py += args[q + 3];
} else {
px = 0;
py = 0;
}
}
if (relative) {
prevX = px;
prevY = py;
} else {
prevX = args[ql - 2];
prevY = args[ql - 1];
}
}
// 二次贝塞尔平滑
else if (cmd === 'T') {
// 这里需要移除上一个曲线的终点
var last = contour.pop();
var pc = contour[contour.length - 1];
if (!pc) {
pc = last;
}
contour.push(pc = {
x: 2 * last.x - pc.x,
y: 2 * last.y - pc.y
});
px = prevX;
py = prevY;
for (q = 0, ql = args.length - 2; q < ql; q += 2) {
if (relative) {
px += args[q];
py += args[q + 1];
} else {
px = args[q];
py = args[q + 1];
}
last = {
x: px,
y: py
};
contour.push(pc = {
x: 2 * last.x - pc.x,
y: 2 * last.y - pc.y
});
}
if (relative) {
prevX = px + args[ql];
prevY = py + args[ql + 1];
} else {
prevX = args[ql];
prevY = args[ql + 1];
}
contour.push({
x: prevX,
y: prevY,
onCurve: true
});
}
// 三次贝塞尔
else if (cmd === 'C') {
if (args.length % 6) {
throw new Error('`C` command params error:' + args.join(','));
}
// 这里可能会连续绘制,最后一个是终点
cubicList = [];
if (relative) {
px = prevX;
py = prevY;
} else {
px = 0;
py = 0;
}
p1 = {
x: prevX,
y: prevY
};
for (q = 0, ql = args.length; q < ql; q += 6) {
c1 = {
x: px + args[q],
y: py + args[q + 1]
};
c2 = {
x: px + args[q + 2],
y: py + args[q + 3]
};
p2 = {
x: px + args[q + 4],
y: py + args[q + 5]
};
cubicList.push([p1, c1, c2, p2]);
p1 = p2;
if (relative) {
px += args[q + 4];
py += args[q + 5];
} else {
px = 0;
py = 0;
}
}
if (relative) {
prevX = px;
prevY = py;
} else {
prevX = args[ql - 2];
prevY = args[ql - 1];
}
cubic2Points(cubicList, contour);
prevCubicC1 = cubicList[cubicList.length - 1][2];
}
// 三次贝塞尔平滑
else if (cmd === 'S') {
if (args.length % 4) {
throw new Error('`S` command params error:' + args.join(','));
}
// 这里可能会连续绘制,最后一个是终点
cubicList = [];
if (relative) {
px = prevX;
py = prevY;
} else {
px = 0;
py = 0;
}
// 这里需要移除上一个曲线的终点
p1 = contour.pop();
if (!prevCubicC1) {
prevCubicC1 = p1;
}
c1 = {
x: 2 * p1.x - prevCubicC1.x,
y: 2 * p1.y - prevCubicC1.y
};
for (q = 0, ql = args.length; q < ql; q += 4) {
c2 = {
x: px + args[q],
y: py + args[q + 1]
};
p2 = {
x: px + args[q + 2],
y: py + args[q + 3]
};
cubicList.push([p1, c1, c2, p2]);
p1 = p2;
c1 = {
x: 2 * p1.x - c2.x,
y: 2 * p1.y - c2.y
};
if (relative) {
px += args[q + 2];
py += args[q + 3];
} else {
px = 0;
py = 0;
}
}
if (relative) {
prevX = px;
prevY = py;
} else {
prevX = args[ql - 2];
prevY = args[ql - 1];
}
cubic2Points(cubicList, contour);
prevCubicC1 = cubicList[cubicList.length - 1][2];
}
// 求弧度, rx, ry, angle, largeArc, sweep, ex, ey
else if (cmd === 'A') {
if (args.length % 7) {
throw new Error('arc command params error:' + args.join(','));
}
for (q = 0, ql = args.length; q < ql; q += 7) {
var ex = args[q + 5];
var ey = args[q + 6];
if (relative) {
ex = prevX + ex;
ey = prevY + ey;
}
var path = (0, _getArc.default)(args[q], args[q + 1], args[q + 2], args[q + 3], args[q + 4], {
x: prevX,
y: prevY
}, {
x: ex,
y: ey
});
if (path && path.length > 1) {
for (var r = 1, rl = path.length; r < rl; r++) {
contour.push(path[r]);
}
}
prevX = ex;
prevY = ey;
}
}
}
return contours;
}
/**
* svg path转轮廓
*
* @param {string} path svg的path字符串
* @return {Array} 转换后的轮廓
*/
function path2contours(path) {
if (!path || !path.length) {
return null;
}
path = path.trim();
// 修正头部不为`m`的情况
if (path[0] !== 'M' && path[0] !== 'm') {
path = 'M 0 0' + path;
}
// 修复中间没有结束符`z`的情况
path = path.replace(/(\d+)\s*(m|$)/gi, '$1z$2');
// 获取segments
var segments = [];
var cmd;
var relative = false;
var lastIndex;
var args;
for (var i = 0, l = path.length; i < l; i++) {
var c = path[i].toUpperCase();
var r = c !== path[i];
switch (c) {
case 'M':
/* jshint -W086 */
if (i === 0) {
cmd = c;
lastIndex = 1;
break;
}
// eslint-disable-next-line no-fallthrough
case 'Q':
case 'T':
case 'C':
case 'S':
case 'H':
case 'V':
case 'L':
case 'A':
case 'Z':
if (cmd === 'Z') {
segments.push({
cmd: 'Z'
});
} else {
args = path.slice(lastIndex, i);
segments.push({
cmd: cmd,
relative: relative,
args: (0, _parseParams.default)(args)
});
}
cmd = c;
relative = r;
lastIndex = i + 1;
break;
}
}
segments.push({
cmd: 'Z'
});
return segments2Contours(segments);
}

View File

@ -0,0 +1,34 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = polygon2contour;
var _parseParams = _interopRequireDefault(require("./parseParams"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file 多边形转换成轮廓
* @author mengke01(kekee000@gmail.com)
*/
/**
* 多边形转换成轮廓
*
* @param {Array} points 多边形点集合
* @return {Array} contours
*/
function polygon2contour(points) {
if (!points || !points.length) {
return null;
}
var contours = [];
var segments = (0, _parseParams.default)(points);
for (var i = 0, l = segments.length; i < l; i += 2) {
contours.push({
x: segments[i],
y: segments[i + 1],
onCurve: true
});
}
return contours;
}

View File

@ -0,0 +1,43 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = rect2contour;
/**
* @file 矩形转换成轮廓
* @author mengke01(kekee000@gmail.com)
*/
/**
* 矩形转换成轮廓
*
* @param {number} x 左上角x
* @param {number} y 左上角y
* @param {number} width 宽度
* @param {number} height 高度
* @return {Array} 轮廓数组
*/
function rect2contour(x, y, width, height) {
x = +x;
y = +y;
width = +width;
height = +height;
return [{
x: x,
y: y,
onCurve: true
}, {
x: x + width,
y: y,
onCurve: true
}, {
x: x + width,
y: y + height,
onCurve: true
}, {
x: x,
y: y + height,
onCurve: true
}];
}

View File

@ -0,0 +1,123 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = svgnode2contours;
var _path2contours = _interopRequireDefault(require("./path2contours"));
var _oval2contour = _interopRequireDefault(require("./oval2contour"));
var _polygon2contour = _interopRequireDefault(require("./polygon2contour"));
var _rect2contour = _interopRequireDefault(require("./rect2contour"));
var _parseTransform = _interopRequireDefault(require("./parseTransform"));
var _contoursTransform = _interopRequireDefault(require("./contoursTransform"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file svg节点转字形轮廓
* @author mengke01(kekee000@gmail.com)
*/
// 支持的解析器集合
var support = {
path: {
parse: _path2contours.default,
// 解析器
params: ['d'],
// 参数列表
contours: true // 是否是多个轮廓
},
circle: {
parse: _oval2contour.default,
params: ['cx', 'cy', 'r']
},
ellipse: {
parse: _oval2contour.default,
params: ['cx', 'cy', 'rx', 'ry']
},
rect: {
parse: _rect2contour.default,
params: ['x', 'y', 'width', 'height']
},
polygon: {
parse: _polygon2contour.default,
params: ['points']
},
polyline: {
parse: _polygon2contour.default,
params: ['points']
}
};
/**
* svg节点转字形轮廓
*
* @param {Array} xmlNodes xml节点集合
* @return {Array|false} 轮廓数组
*/
function svgnode2contours(xmlNodes) {
var i;
var length;
var j;
var jlength;
var segment; // 当前指令
var parsedSegments = []; // 解析后的指令
if (xmlNodes.length) {
var _loop = function _loop() {
var node = xmlNodes[i];
var name = node.tagName;
if (support[name]) {
var supportParams = support[name].params;
var params = [];
for (j = 0, jlength = supportParams.length; j < jlength; j++) {
params.push(node.getAttribute(supportParams[j]));
}
segment = {
name: name,
params: params,
transform: (0, _parseTransform.default)(node.getAttribute('transform'))
};
if (node.parentNode) {
var curNode = node.parentNode;
var transforms = segment.transform || [];
var transAttr;
var iterator = function iterator(t) {
transforms.unshift(t);
};
while (curNode !== null && curNode.tagName !== 'svg') {
transAttr = curNode.getAttribute('transform');
if (transAttr) {
(0, _parseTransform.default)(transAttr).reverse().forEach(iterator);
}
curNode = curNode.parentNode;
}
segment.transform = transforms.length ? transforms : null;
}
parsedSegments.push(segment);
}
};
for (i = 0, length = xmlNodes.length; i < length; i++) {
_loop();
}
}
if (parsedSegments.length) {
var result = [];
for (i = 0, length = parsedSegments.length; i < length; i++) {
segment = parsedSegments[i];
var parser = support[segment.name];
var contour = parser.parse.apply(null, segment.params);
if (contour && contour.length) {
var contours = parser.contours ? contour : [contour];
// 如果有变换则应用变换规则
if (segment.transform) {
contours = (0, _contoursTransform.default)(contours, segment.transform);
}
for (j = 0, jlength = contours.length; j < jlength; j++) {
result.push(contours[j]);
}
}
}
return result;
}
return false;
}

View File

@ -0,0 +1,25 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = svg2base64;
/**
* @file svg字符串转base64编码
* @author mengke01(kekee000@gmail.com)
*/
/**
* svg字符串转base64编码
*
* @param {string} svg svg对象
* @param {string} scheme 头部
* @return {string} base64编码
*/
function svg2base64(svg) {
var scheme = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'font/svg';
if (typeof btoa === 'undefined') {
return 'data:' + scheme + ';charset=utf-8;base64,' + Buffer.from(svg, 'binary').toString('base64');
}
return 'data:' + scheme + ';charset=utf-8;base64,' + btoa(svg);
}

View File

@ -0,0 +1,393 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = svg2ttfObject;
var _string = _interopRequireDefault(require("../common/string"));
var _DOMParser = _interopRequireDefault(require("../common/DOMParser"));
var _path2contours = _interopRequireDefault(require("./svg/path2contours"));
var _svgnode2contours = _interopRequireDefault(require("./svg/svgnode2contours"));
var _computeBoundingBox = require("../graphics/computeBoundingBox");
var _pathsUtil = _interopRequireDefault(require("../graphics/pathsUtil"));
var _glyfAdjust = _interopRequireDefault(require("./util/glyfAdjust"));
var _error = _interopRequireDefault(require("./error"));
var _getEmptyttfObject = _interopRequireDefault(require("./getEmptyttfObject"));
var _reduceGlyf = _interopRequireDefault(require("./util/reduceGlyf"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } /**
* @file svg格式转ttfObject格式
* @author mengke01(kekee000@gmail.com)
*/
/**
* 加载xml字符串
*
* @param {string} xml xml字符串
* @return {Document}
*/
function loadXML(xml) {
if (_DOMParser.default) {
try {
var domParser = new _DOMParser.default();
var xmlDoc = domParser.parseFromString(xml, 'text/xml');
return xmlDoc;
} catch (exp) {
_error.default.raise(10103);
}
}
_error.default.raise(10004);
}
/**
* 对xml文本进行处理
*
* @param {string} svg svg文本
* @return {string} 处理后文本
*/
function resolveSVG(svg) {
// 去除xmlns防止xmlns导致svg解析错误
svg = svg.replace(/\s+xmlns(?::[\w-]+)?=("|')[^"']*\1/g, ' ').replace(/<defs[>\s][\s\S]+?\/defs>/g, function (text) {
if (text.indexOf('</font>') >= 0) {
return text;
}
return '';
}).replace(/<use[>\s][\s\S]+?\/use>/g, '');
return svg;
}
/**
* 获取空的ttf格式对象
*
* @return {Object} ttfObject对象
*/
function getEmptyTTF() {
var ttf = (0, _getEmptyttfObject.default)();
ttf.head.unitsPerEm = 0; // 去除unitsPerEm以便于重新计算
ttf.from = 'svgfont';
return ttf;
}
/**
* 获取空的对象用来作为ttf的容器
*
* @return {Object} ttfObject对象
*/
function getEmptyObject() {
return {
'from': 'svg',
'OS/2': {},
'name': {},
'hhea': {},
'head': {},
'post': {},
'glyf': []
};
}
/**
* 根据边界获取unitsPerEm
*
* @param {number} xMin x最小值
* @param {number} xMax x最大值
* @param {number} yMin y最小值
* @param {number} yMax y最大值
* @return {number}
*/
function getUnitsPerEm(xMin, xMax, yMin, yMax) {
var seed = Math.ceil(Math.min(yMax - yMin, xMax - xMin));
if (!seed) {
return 1024;
}
if (seed <= 128) {
return seed;
}
// 获取合适的unitsPerEm
var unitsPerEm = 128;
while (unitsPerEm < 16384) {
if (seed <= 1.2 * unitsPerEm) {
return unitsPerEm;
}
unitsPerEm <<= 1;
}
return 1024;
}
/**
* 对ttfObject进行处理去除小数
*
* @param {Object} ttf ttfObject
* @return {Object} ttfObject
*/
function resolve(ttf) {
// 如果是svg格式字体则去小数
// 由于svg格式导入时候会出现字形重复问题这里进行优化
if (ttf.from === 'svgfont' && ttf.head.unitsPerEm > 128) {
ttf.glyf.forEach(function (g) {
if (g.contours) {
(0, _glyfAdjust.default)(g);
(0, _reduceGlyf.default)(g);
}
});
}
// 否则重新计算字形大小缩放到1024的em
else {
var xMin = 16384;
var xMax = -16384;
var yMin = 16384;
var yMax = -16384;
ttf.glyf.forEach(function (g) {
if (g.contours) {
var bound = _computeBoundingBox.computePathBox.apply(void 0, _toConsumableArray(g.contours));
if (bound) {
xMin = Math.min(xMin, bound.x);
xMax = Math.max(xMax, bound.x + bound.width);
yMin = Math.min(yMin, bound.y);
yMax = Math.max(yMax, bound.y + bound.height);
}
}
});
var unitsPerEm = getUnitsPerEm(xMin, xMax, yMin, yMax);
var scale = 1024 / unitsPerEm;
ttf.glyf.forEach(function (g) {
(0, _glyfAdjust.default)(g, scale, scale);
(0, _reduceGlyf.default)(g);
});
ttf.head.unitsPerEm = 1024;
}
return ttf;
}
/**
* 解析字体信息相关节点
*
* @param {Document} xmlDoc XML文档对象
* @param {Object} ttf ttf对象
* @return {Object} ttf对象
*/
function parseFont(xmlDoc, ttf) {
var metaNode = xmlDoc.getElementsByTagName('metadata')[0];
var fontNode = xmlDoc.getElementsByTagName('font')[0];
var fontFaceNode = xmlDoc.getElementsByTagName('font-face')[0];
if (metaNode && metaNode.textContent) {
ttf.metadata = _string.default.decodeHTML(metaNode.textContent.trim());
}
// 解析font如果有font节点说明是svg格式字体文件
if (fontNode) {
ttf.id = fontNode.getAttribute('id') || '';
ttf.hhea.advanceWidthMax = +(fontNode.getAttribute('horiz-adv-x') || 0);
ttf.from = 'svgfont';
}
if (fontFaceNode) {
var OS2 = ttf['OS/2'];
ttf.name.fontFamily = fontFaceNode.getAttribute('font-family') || '';
OS2.usWeightClass = +(fontFaceNode.getAttribute('font-weight') || 0);
ttf.head.unitsPerEm = +(fontFaceNode.getAttribute('units-per-em') || 0);
// 解析panose, eg: 2 0 6 3 0 0 0 0 0 0
var panose = (fontFaceNode.getAttribute('panose-1') || '').split(' ');
['bFamilyType', 'bSerifStyle', 'bWeight', 'bProportion', 'bContrast', 'bStrokeVariation', 'bArmStyle', 'bLetterform', 'bMidline', 'bXHeight'].forEach(function (name, i) {
OS2[name] = +(panose[i] || 0);
});
ttf.hhea.ascent = +(fontFaceNode.getAttribute('ascent') || 0);
ttf.hhea.descent = +(fontFaceNode.getAttribute('descent') || 0);
OS2.bXHeight = +(fontFaceNode.getAttribute('x-height') || 0);
// 解析bounding
var box = (fontFaceNode.getAttribute('bbox') || '').split(' ');
['xMin', 'yMin', 'xMax', 'yMax'].forEach(function (name, i) {
ttf.head[name] = +(box[i] || '');
});
ttf.post.underlineThickness = +(fontFaceNode.getAttribute('underline-thickness') || 0);
ttf.post.underlinePosition = +(fontFaceNode.getAttribute('underline-position') || 0);
// unicode range
var unicodeRange = fontFaceNode.getAttribute('unicode-range');
if (unicodeRange) {
unicodeRange.replace(/u\+([0-9A-Z]+)(-[0-9A-Z]+)?/i, function ($0, a, b) {
OS2.usFirstCharIndex = Number('0x' + a);
OS2.usLastCharIndex = b ? Number('0x' + b.slice(1)) : 0xFFFFFFFF;
});
}
}
return ttf;
}
/**
* 解析字体信息相关节点
*
* @param {Document} xmlDoc XML文档对象
* @param {Object} ttf ttf对象
* @return {Object} ttf对象
*/
function parseGlyf(xmlDoc, ttf) {
var missingNode = xmlDoc.getElementsByTagName('missing-glyph')[0];
// 解析glyf
var d;
var unicode;
if (missingNode) {
var missing = {
name: '.notdef'
};
if (missingNode.getAttribute('horiz-adv-x')) {
missing.advanceWidth = +missingNode.getAttribute('horiz-adv-x');
}
if (d = missingNode.getAttribute('d')) {
missing.contours = (0, _path2contours.default)(d);
}
// 去除默认的空字形
if (ttf.glyf[0] && ttf.glyf[0].name === '.notdef') {
ttf.glyf.splice(0, 1);
}
ttf.glyf.unshift(missing);
}
var glyfNodes = xmlDoc.getElementsByTagName('glyph');
if (glyfNodes.length) {
for (var i = 0, l = glyfNodes.length; i < l; i++) {
var node = glyfNodes[i];
var glyf = {
name: node.getAttribute('glyph-name') || node.getAttribute('name') || ''
};
if (node.getAttribute('horiz-adv-x')) {
glyf.advanceWidth = +node.getAttribute('horiz-adv-x');
}
if (unicode = node.getAttribute('unicode')) {
var nextUnicode = [];
var totalCodePoints = 0;
for (var ui = 0; ui < unicode.length; ui++) {
var ucp = unicode.codePointAt(ui);
nextUnicode.push(ucp);
ui = ucp > 0xffff ? ui + 1 : ui;
totalCodePoints += 1;
}
if (totalCodePoints === 1) {
// TTF can't handle ligatures
glyf.unicode = nextUnicode;
if (d = node.getAttribute('d')) {
glyf.contours = (0, _path2contours.default)(d);
}
ttf.glyf.push(glyf);
}
}
}
}
return ttf;
}
/**
* 解析字体信息相关节点
*
* @param {Document} xmlDoc XML文档对象
* @param {Object} ttf ttf对象
*/
function parsePath(xmlDoc, ttf) {
// 单个path组成一个glfy字形
var contours;
var glyf;
var node;
var pathNodes = xmlDoc.getElementsByTagName('path');
if (pathNodes.length) {
for (var i = 0, l = pathNodes.length; i < l; i++) {
node = pathNodes[i];
glyf = {
name: node.getAttribute('name') || ''
};
contours = (0, _svgnode2contours.default)([node]);
glyf.contours = contours;
ttf.glyf.push(glyf);
}
}
// 其他svg指令组成一个glyf字形
contours = (0, _svgnode2contours.default)(Array.prototype.slice.call(xmlDoc.getElementsByTagName('*')).filter(function (node) {
return node.tagName !== 'path';
}));
if (contours) {
glyf = {
name: ''
};
glyf.contours = contours;
ttf.glyf.push(glyf);
}
}
/**
* 解析xml文档
*
* @param {Document} xmlDoc XML文档对象
* @param {Object} options 导入选项
*
* @return {Object} 解析后对象
*/
function parseXML(xmlDoc, options) {
if (!xmlDoc.getElementsByTagName('svg').length) {
_error.default.raise(10106);
}
var ttf;
// 如果是svg字体格式则解析glyf否则解析path
if (xmlDoc.getElementsByTagName('font')[0]) {
ttf = getEmptyTTF();
parseFont(xmlDoc, ttf);
parseGlyf(xmlDoc, ttf);
} else {
ttf = getEmptyObject();
parsePath(xmlDoc, ttf);
}
if (!ttf.glyf.length) {
_error.default.raise(10201);
}
if (ttf.from === 'svg') {
var glyf = ttf.glyf;
var i;
var l;
// 合并导入的字形为单个字形
if (options.combinePath) {
var combined = [];
for (i = 0, l = glyf.length; i < l; i++) {
var contours = glyf[i].contours;
for (var index = 0, length = contours.length; index < length; index++) {
combined.push(contours[index]);
}
}
glyf[0].contours = combined;
glyf.splice(1);
}
// 对字形进行反转
for (i = 0, l = glyf.length; i < l; i++) {
// 这里为了使ai等工具里面的字形方便导入对svg做了反向处理
glyf[i].contours = _pathsUtil.default.flip(glyf[i].contours);
}
}
return ttf;
}
/**
* svg格式转ttfObject格式
*
* @param {string|Document} svg svg格式
* @param {Object=} options 导入选项
* @param {boolean} options.combinePath 是否合并成单个字形仅限于普通svg导入
* @return {Object} ttfObject
*/
function svg2ttfObject(svg) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
combinePath: false
};
var xmlDoc = svg;
if (typeof svg === 'string') {
svg = resolveSVG(svg);
xmlDoc = loadXML(svg);
}
var ttf = parseXML(xmlDoc, options);
return resolve(ttf);
}

View File

@ -0,0 +1,230 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _table = _interopRequireDefault(require("./table"));
var _string = _interopRequireDefault(require("../util/string"));
var _encoding = _interopRequireDefault(require("./cff/encoding"));
var _cffStandardStrings = _interopRequireDefault(require("./cff/cffStandardStrings"));
var _parseCFFDict = _interopRequireDefault(require("./cff/parseCFFDict"));
var _parseCFFGlyph = _interopRequireDefault(require("./cff/parseCFFGlyph"));
var _parseCFFCharset = _interopRequireDefault(require("./cff/parseCFFCharset"));
var _parseCFFEncoding = _interopRequireDefault(require("./cff/parseCFFEncoding"));
var _reader = _interopRequireDefault(require("../reader"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file cff表
* @author mengke01(kekee000@gmail.com)
*
* reference:
* http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/font/pdfs/5176.CFF.pdf
*
* modify from:
* https://github.com/nodebox/opentype.js/blob/master/src/tables/cff.js
*/
/**
* 获取cff偏移
*
* @param {Reader} reader 读取器
* @param {number} offSize 偏移大小
* @param {number} offset 起始偏移
* @return {number} 偏移
*/
function getOffset(reader, offSize) {
var v = 0;
for (var i = 0; i < offSize; i++) {
v <<= 8;
v += reader.readUint8();
}
return v;
}
/**
* 解析cff表头部
*
* @param {Reader} reader 读取器
* @return {Object} 头部字段
*/
function parseCFFHead(reader) {
var head = {};
head.startOffset = reader.offset;
head.endOffset = head.startOffset + 4;
head.formatMajor = reader.readUint8();
head.formatMinor = reader.readUint8();
head.size = reader.readUint8();
head.offsetSize = reader.readUint8();
return head;
}
/**
* 解析`CFF`表索引
*
* @param {Reader} reader 读取器
* @param {number} offset 偏移
* @param {Funciton} conversionFn 转换函数
* @return {Object} 表对象
*/
function parseCFFIndex(reader, offset, conversionFn) {
if (offset) {
reader.seek(offset);
}
var start = reader.offset;
var offsets = [];
var objects = [];
var count = reader.readUint16();
var i;
var l;
if (count !== 0) {
var offsetSize = reader.readUint8();
for (i = 0, l = count + 1; i < l; i++) {
offsets.push(getOffset(reader, offsetSize));
}
for (i = 0, l = count; i < l; i++) {
var value = reader.readBytes(offsets[i + 1] - offsets[i]);
if (conversionFn) {
value = conversionFn(value);
}
objects.push(value);
}
}
return {
objects: objects,
startOffset: start,
endOffset: reader.offset
};
}
// Subroutines are encoded using the negative half of the number space.
// See type 2 chapter 4.7 "Subroutine operators".
function calcCFFSubroutineBias(subrs) {
var bias;
if (subrs.length < 1240) {
bias = 107;
} else if (subrs.length < 33900) {
bias = 1131;
} else {
bias = 32768;
}
return bias;
}
var _default = exports.default = _table.default.create('cff', [], {
read: function read(reader, font) {
var offset = this.offset;
reader.seek(offset);
var head = parseCFFHead(reader);
var nameIndex = parseCFFIndex(reader, head.endOffset, _string.default.getString);
var topDictIndex = parseCFFIndex(reader, nameIndex.endOffset);
var stringIndex = parseCFFIndex(reader, topDictIndex.endOffset, _string.default.getString);
var globalSubrIndex = parseCFFIndex(reader, stringIndex.endOffset);
var cff = {
head: head
};
// 全局子glyf数据
cff.gsubrs = globalSubrIndex.objects;
cff.gsubrsBias = calcCFFSubroutineBias(globalSubrIndex.objects);
// 顶级字典数据
var dictReader = new _reader.default(new Uint8Array(topDictIndex.objects[0]).buffer);
var topDict = _parseCFFDict.default.parseTopDict(dictReader, 0, dictReader.length, stringIndex.objects);
cff.topDict = topDict;
// 私有字典数据
var privateDictLength = topDict.private[0];
var privateDict = {};
var privateDictOffset;
if (privateDictLength) {
privateDictOffset = offset + topDict.private[1];
privateDict = _parseCFFDict.default.parsePrivateDict(reader, privateDictOffset, privateDictLength, stringIndex.objects);
cff.defaultWidthX = privateDict.defaultWidthX;
cff.nominalWidthX = privateDict.nominalWidthX;
} else {
cff.defaultWidthX = 0;
cff.nominalWidthX = 0;
}
// 私有子glyf数据
if (privateDict.subrs) {
var subrOffset = privateDictOffset + privateDict.subrs;
var subrIndex = parseCFFIndex(reader, subrOffset);
cff.subrs = subrIndex.objects;
cff.subrsBias = calcCFFSubroutineBias(cff.subrs);
} else {
cff.subrs = [];
cff.subrsBias = 0;
}
cff.privateDict = privateDict;
// 解析glyf数据和名字
var charStringsIndex = parseCFFIndex(reader, offset + topDict.charStrings);
var nGlyphs = charStringsIndex.objects.length;
if (topDict.charset < 3) {
// @author: fr33z00
// See end of chapter 13 (p22) of #5176.CFF.pdf :
// Still more optimization is possible by
// observing that many fonts adopt one of 3 common charsets. In
// these cases the operand to the charset operator in the Top DICT
// specifies a predefined charset id, in place of an offset, as shown in table 22
cff.charset = _cffStandardStrings.default;
} else {
cff.charset = (0, _parseCFFCharset.default)(reader, offset + topDict.charset, nGlyphs, stringIndex.objects);
}
// Standard encoding
if (topDict.encoding === 0) {
cff.encoding = _encoding.default.standardEncoding;
}
// Expert encoding
else if (topDict.encoding === 1) {
cff.encoding = _encoding.default.expertEncoding;
} else {
cff.encoding = (0, _parseCFFEncoding.default)(reader, offset + topDict.encoding);
}
cff.glyf = [];
// only parse subset glyphs
var subset = font.readOptions.subset;
if (subset && subset.length > 0) {
// subset map
var subsetMap = {
0: true // 设置.notdef
};
var codes = font.cmap;
// unicode to index
Object.keys(codes).forEach(function (c) {
if (subset.indexOf(+c) > -1) {
var i = codes[c];
subsetMap[i] = true;
}
});
font.subsetMap = subsetMap;
Object.keys(subsetMap).forEach(function (i) {
i = +i;
var glyf = (0, _parseCFFGlyph.default)(charStringsIndex.objects[i], cff, i);
glyf.name = cff.charset[i];
cff.glyf[i] = glyf;
});
}
// parse all
else {
for (var i = 0, l = nGlyphs; i < l; i++) {
var glyf = (0, _parseCFFGlyph.default)(charStringsIndex.objects[i], cff, i);
glyf.name = cff.charset[i];
cff.glyf.push(glyf);
}
}
return cff;
},
// eslint-disable-next-line no-unused-vars
write: function write(writer, font) {
throw new Error('not support write cff table');
},
// eslint-disable-next-line no-unused-vars
size: function size(font) {
throw new Error('not support get cff table size');
}
});

View File

@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _table = _interopRequireDefault(require("./table"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file GPOS
* @author fr33z00(https://github.com/fr33z00)
*
* @reference: https://learn.microsoft.com/en-us/typography/opentype/spec/gpos
*/
var _default = exports.default = _table.default.create('GPOS', [], {
read: function read(reader, ttf) {
var length = ttf.tables.GPOS.length;
return reader.readBytes(this.offset, length);
},
write: function write(writer, ttf) {
if (ttf.GPOS) {
writer.writeBytes(ttf.GPOS, ttf.GPOS.length);
}
},
size: function size(ttf) {
return ttf.GPOS ? ttf.GPOS.length : 0;
}
});

View File

@ -0,0 +1,251 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _table = _interopRequireDefault(require("./table"));
var _struct = _interopRequireDefault(require("./struct"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file OS/2
* @author mengke01(kekee000@gmail.com)
*
* http://www.microsoft.com/typography/otspec/os2.htm
*/
var _default = exports.default = _table.default.create('OS/2', [['version', _struct.default.Uint16], ['xAvgCharWidth', _struct.default.Int16], ['usWeightClass', _struct.default.Uint16], ['usWidthClass', _struct.default.Uint16], ['fsType', _struct.default.Uint16], ['ySubscriptXSize', _struct.default.Uint16], ['ySubscriptYSize', _struct.default.Uint16], ['ySubscriptXOffset', _struct.default.Uint16], ['ySubscriptYOffset', _struct.default.Uint16], ['ySuperscriptXSize', _struct.default.Uint16], ['ySuperscriptYSize', _struct.default.Uint16], ['ySuperscriptXOffset', _struct.default.Uint16], ['ySuperscriptYOffset', _struct.default.Uint16], ['yStrikeoutSize', _struct.default.Uint16], ['yStrikeoutPosition', _struct.default.Uint16], ['sFamilyClass', _struct.default.Uint16],
// Panose
['bFamilyType', _struct.default.Uint8], ['bSerifStyle', _struct.default.Uint8], ['bWeight', _struct.default.Uint8], ['bProportion', _struct.default.Uint8], ['bContrast', _struct.default.Uint8], ['bStrokeVariation', _struct.default.Uint8], ['bArmStyle', _struct.default.Uint8], ['bLetterform', _struct.default.Uint8], ['bMidline', _struct.default.Uint8], ['bXHeight', _struct.default.Uint8],
// unicode range
['ulUnicodeRange1', _struct.default.Uint32], ['ulUnicodeRange2', _struct.default.Uint32], ['ulUnicodeRange3', _struct.default.Uint32], ['ulUnicodeRange4', _struct.default.Uint32],
// char 4
['achVendID', _struct.default.String, 4], ['fsSelection', _struct.default.Uint16], ['usFirstCharIndex', _struct.default.Uint16], ['usLastCharIndex', _struct.default.Uint16], ['sTypoAscender', _struct.default.Int16], ['sTypoDescender', _struct.default.Int16], ['sTypoLineGap', _struct.default.Int16], ['usWinAscent', _struct.default.Uint16], ['usWinDescent', _struct.default.Uint16],
// version 0 above 39
['ulCodePageRange1', _struct.default.Uint32], ['ulCodePageRange2', _struct.default.Uint32],
// version 1 above 41
['sxHeight', _struct.default.Int16], ['sCapHeight', _struct.default.Int16], ['usDefaultChar', _struct.default.Uint16], ['usBreakChar', _struct.default.Uint16], ['usMaxContext', _struct.default.Uint16]
// version 2,3,4 above 46
], {
read: function read(reader, ttf) {
var format = reader.readUint16(this.offset);
var struct = this.struct;
// format2
if (format === 0) {
struct = struct.slice(0, 39);
} else if (format === 1) {
struct = struct.slice(0, 41);
}
var OS2Head = _table.default.create('os2head', struct);
var tbl = new OS2Head(this.offset).read(reader, ttf);
// 补齐其他version的字段
var os2Fields = {
ulCodePageRange1: 1,
ulCodePageRange2: 0,
sxHeight: 0,
sCapHeight: 0,
usDefaultChar: 0,
usBreakChar: 32,
usMaxContext: 0
};
return Object.assign(os2Fields, tbl);
},
size: function size(ttf) {
// 更新其他表的统计信息
// header
var xMin = 16384;
var yMin = 16384;
var xMax = -16384;
var yMax = -16384;
// hhea
var advanceWidthMax = -1;
var minLeftSideBearing = 16384;
var minRightSideBearing = 16384;
var xMaxExtent = -16384;
// os2 count
var xAvgCharWidth = 0;
var usFirstCharIndex = 0x10FFFF;
var usLastCharIndex = -1;
// maxp
var maxPoints = 0;
var maxContours = 0;
var maxCompositePoints = 0;
var maxCompositeContours = 0;
var maxSizeOfInstructions = 0;
var maxComponentElements = 0;
var glyfNotEmpty = 0; // 非空glyf
var hinting = ttf.writeOptions ? ttf.writeOptions.hinting : false;
// 计算instructions和functiondefs
if (hinting) {
if (ttf.cvt) {
maxSizeOfInstructions = Math.max(maxSizeOfInstructions, ttf.cvt.length);
}
if (ttf.prep) {
maxSizeOfInstructions = Math.max(maxSizeOfInstructions, ttf.prep.length);
}
if (ttf.fpgm) {
maxSizeOfInstructions = Math.max(maxSizeOfInstructions, ttf.fpgm.length);
}
}
ttf.glyf.forEach(function (glyf) {
// 统计control point信息
if (glyf.compound) {
var compositeContours = 0;
var compositePoints = 0;
glyf.glyfs.forEach(function (g) {
var cglyf = ttf.glyf[g.glyphIndex];
if (!cglyf) {
return;
}
compositeContours += cglyf.contours ? cglyf.contours.length : 0;
if (cglyf.contours && cglyf.contours.length) {
cglyf.contours.forEach(function (contour) {
compositePoints += contour.length;
});
}
});
maxComponentElements = Math.max(maxComponentElements, glyf.glyfs.length);
maxCompositePoints = Math.max(maxCompositePoints, compositePoints);
maxCompositeContours = Math.max(maxCompositeContours, compositeContours);
}
// 简单图元
else if (glyf.contours && glyf.contours.length) {
maxContours = Math.max(maxContours, glyf.contours.length);
var points = 0;
glyf.contours.forEach(function (contour) {
points += contour.length;
});
maxPoints = Math.max(maxPoints, points);
}
if (hinting && glyf.instructions) {
maxSizeOfInstructions = Math.max(maxSizeOfInstructions, glyf.instructions.length);
}
// 统计边界信息
if (null != glyf.xMin && glyf.xMin < xMin) {
xMin = glyf.xMin;
}
if (null != glyf.yMin && glyf.yMin < yMin) {
yMin = glyf.yMin;
}
if (null != glyf.xMax && glyf.xMax > xMax) {
xMax = glyf.xMax;
}
if (null != glyf.yMax && glyf.yMax > yMax) {
yMax = glyf.yMax;
}
advanceWidthMax = Math.max(advanceWidthMax, glyf.advanceWidth);
minLeftSideBearing = Math.min(minLeftSideBearing, glyf.leftSideBearing);
if (null != glyf.xMax) {
minRightSideBearing = Math.min(minRightSideBearing, glyf.advanceWidth - glyf.xMax);
xMaxExtent = Math.max(xMaxExtent, glyf.xMax);
}
if (null != glyf.advanceWidth) {
xAvgCharWidth += glyf.advanceWidth;
glyfNotEmpty++;
}
var unicodes = glyf.unicode;
if (typeof glyf.unicode === 'number') {
unicodes = [glyf.unicode];
}
if (Array.isArray(unicodes)) {
unicodes.forEach(function (unicode) {
if (unicode !== 0xFFFF) {
usFirstCharIndex = Math.min(usFirstCharIndex, unicode);
usLastCharIndex = Math.max(usLastCharIndex, unicode);
}
});
}
});
// 重新设置version 4
ttf['OS/2'].version = 0x4;
ttf['OS/2'].achVendID = (ttf['OS/2'].achVendID + ' ').slice(0, 4);
ttf['OS/2'].xAvgCharWidth = xAvgCharWidth / (glyfNotEmpty || 1);
ttf['OS/2'].ulUnicodeRange2 = 268435456;
ttf['OS/2'].usFirstCharIndex = usFirstCharIndex;
ttf['OS/2'].usLastCharIndex = usLastCharIndex;
// rewrite hhea
ttf.hhea.version = ttf.hhea.version || 0x1;
ttf.hhea.advanceWidthMax = advanceWidthMax;
ttf.hhea.minLeftSideBearing = minLeftSideBearing;
ttf.hhea.minRightSideBearing = minRightSideBearing;
ttf.hhea.xMaxExtent = xMaxExtent;
// rewrite head
ttf.head.version = ttf.head.version || 0x1;
ttf.head.lowestRecPPEM = ttf.head.lowestRecPPEM || 0x8;
ttf.head.xMin = xMin;
ttf.head.yMin = yMin;
ttf.head.xMax = xMax;
ttf.head.yMax = yMax;
// head rewrite
if (ttf.support.head) {
var _ttf$support$head = ttf.support.head,
_xMin = _ttf$support$head.xMin,
_yMin = _ttf$support$head.yMin,
_xMax = _ttf$support$head.xMax,
_yMax = _ttf$support$head.yMax;
if (_xMin != null) {
ttf.head.xMin = _xMin;
}
if (_yMin != null) {
ttf.head.yMin = _yMin;
}
if (_xMax != null) {
ttf.head.xMax = _xMax;
}
if (_yMax != null) {
ttf.head.yMax = _yMax;
}
}
// hhea rewrite
if (ttf.support.hhea) {
var _ttf$support$hhea = ttf.support.hhea,
_advanceWidthMax = _ttf$support$hhea.advanceWidthMax,
_xMaxExtent = _ttf$support$hhea.xMaxExtent,
_minLeftSideBearing = _ttf$support$hhea.minLeftSideBearing,
_minRightSideBearing = _ttf$support$hhea.minRightSideBearing;
if (_advanceWidthMax != null) {
ttf.hhea.advanceWidthMax = _advanceWidthMax;
}
if (_xMaxExtent != null) {
ttf.hhea.xMaxExtent = _xMaxExtent;
}
if (_minLeftSideBearing != null) {
ttf.hhea.minLeftSideBearing = _minLeftSideBearing;
}
if (_minRightSideBearing != null) {
ttf.hhea.minRightSideBearing = _minRightSideBearing;
}
}
// 这里根据存储的maxp来设置新的maxp避免重复计算maxp
ttf.maxp = ttf.maxp || {};
ttf.support.maxp = {
version: 1.0,
numGlyphs: ttf.glyf.length,
maxPoints: maxPoints,
maxContours: maxContours,
maxCompositePoints: maxCompositePoints,
maxCompositeContours: maxCompositeContours,
maxZones: ttf.maxp.maxZones || 0,
maxTwilightPoints: ttf.maxp.maxTwilightPoints || 0,
maxStorage: ttf.maxp.maxStorage || 0,
maxFunctionDefs: ttf.maxp.maxFunctionDefs || 0,
maxStackElements: ttf.maxp.maxStackElements || 0,
maxSizeOfInstructions: maxSizeOfInstructions,
maxComponentElements: maxComponentElements,
maxComponentDepth: maxComponentElements ? 1 : 0
};
return _table.default.size.call(this, ttf);
}
});

View File

@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
/**
* @file cffStandardStrings.js
* @author mengke01(kekee000@gmail.com)
*/
var cffStandardStrings = ['.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore', 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent', 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency', 'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 'daggerdbl', 'periodcentered', 'paragraph', 'bullet', 'quotesinglbase', 'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis', 'perthousand', 'questiondown', 'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron', 'emdash', 'AE', 'ordfeminine', 'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae', 'dotlessi', 'lslash', 'oslash', 'oe', 'germandbls', 'onesuperior', 'logicalnot', 'mu', 'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn', 'onequarter', 'divide', 'brokenbar', 'degree', 'thorn', 'threequarters', 'twosuperior', 'registered', 'minus', 'eth', 'multiply', 'threesuperior', 'copyright', 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring', 'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', 'Ocircumflex', 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', 'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron', 'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla', 'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex', 'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis', 'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis', 'ugrave', 'yacute', 'ydieresis', 'zcaron', 'exclamsmall', 'Hungarumlautsmall', 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', '266 ff', 'onedotenleader', 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'commasuperior', 'threequartersemdash', 'periodsuperior', 'questionsmall', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior', 'tsuperior', 'ff', 'ffi', 'ffl', 'parenleftinferior', 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', 'exclamdownsmall', 'centoldstyle', 'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall', 'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'foursuperior', 'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall', 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall', 'Ydieresissmall', '001.000', '001.001', '001.002', '001.003', 'Black', 'Bold', 'Book', 'Light', 'Medium', 'Regular', 'Roman', 'Semibold'];
var _default = exports.default = cffStandardStrings;

View File

@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
/**
* @file cff名字设置
* @author mengke01(kekee000@gmail.com)
*/
var cffStandardEncoding = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore', 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'exclamdown', 'cent', 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency', 'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', '', 'endash', 'dagger', 'daggerdbl', 'periodcentered', '', 'paragraph', 'bullet', 'quotesinglbase', 'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis', 'perthousand', '', 'questiondown', '', 'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', '', 'ring', 'cedilla', '', 'hungarumlaut', 'ogonek', 'caron', 'emdash', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'AE', '', 'ordfeminine', '', '', '', '', 'Lslash', 'Oslash', 'OE', 'ordmasculine', '', '', '', '', '', 'ae', '', '', '', 'dotlessi', '', '', 'lslash', 'oslash', 'oe', 'germandbls'];
var cffExpertEncoding = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'space', 'exclamsmall', 'Hungarumlautsmall', '', 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma', 'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'colon', 'semicolon', 'commasuperior', 'threequartersemdash', 'periodsuperior', 'questionsmall', '', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', '', '', 'isuperior', '', '', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior', '', '', 'rsuperior', 'ssuperior', 'tsuperior', '', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', '', 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'exclamdownsmall', 'centoldstyle', 'Lslashsmall', '', '', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall', 'Caronsmall', '', 'Dotaccentsmall', '', '', 'Macronsmall', '', '', 'figuredash', 'hypheninferior', '', '', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', '', '', '', 'onequarter', 'onehalf', 'threequarters', 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds', '', '', 'zerosuperior', 'onesuperior', 'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall', 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall', 'Ydieresissmall'];
var _default = exports.default = {
standardEncoding: cffStandardEncoding,
expertEncoding: cffExpertEncoding
};

View File

@ -0,0 +1,30 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = getCFFString;
var _cffStandardStrings = _interopRequireDefault(require("./cffStandardStrings"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file 获取cff字符串
* @author mengke01(kekee000@gmail.com)
*/
/**
* 根据索引获取cff字符串
*
* @param {Object} strings 标准cff字符串索引
* @param {number} index 索引号
* @return {number} 字符串索引
*/
function getCFFString(strings, index) {
if (index <= 390) {
index = _cffStandardStrings.default[index];
}
// Strings below index 392 are standard CFF strings and are not encoded in the font.
else {
index = strings[index - 391];
}
return index;
}

View File

@ -0,0 +1,62 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = parseCFFCharset;
var _getCFFString = _interopRequireDefault(require("./getCFFString"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file 解析cff字符集
* @author mengke01(kekee000@gmail.com)
*/
/**
* 解析cff字形名称
* See Adobe TN #5176 chapter 13, "Charsets".
*
* @param {Reader} reader 读取器
* @param {number} start 起始偏移
* @param {number} nGlyphs 字形个数
* @param {Object} strings cff字符串字典
* @return {Array} 字符集
*/
function parseCFFCharset(reader, start, nGlyphs, strings) {
if (start) {
reader.seek(start);
}
var i;
var sid;
var count;
// The .notdef glyph is not included, so subtract 1.
nGlyphs -= 1;
var charset = ['.notdef'];
var format = reader.readUint8();
if (format === 0) {
for (i = 0; i < nGlyphs; i += 1) {
sid = reader.readUint16();
charset.push((0, _getCFFString.default)(strings, sid));
}
} else if (format === 1) {
while (charset.length <= nGlyphs) {
sid = reader.readUint16();
count = reader.readUint8();
for (i = 0; i <= count; i += 1) {
charset.push((0, _getCFFString.default)(strings, sid));
sid += 1;
}
}
} else if (format === 2) {
while (charset.length <= nGlyphs) {
sid = reader.readUint16();
count = reader.readUint16();
for (i = 0; i <= count; i += 1) {
charset.push((0, _getCFFString.default)(strings, sid));
sid += 1;
}
}
} else {
throw new Error('Unknown charset format ' + format);
}
return charset;
}

View File

@ -0,0 +1,299 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _getCFFString = _interopRequireDefault(require("./getCFFString"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file 解析cffdict数据
* @author mengke01(kekee000@gmail.com)
*/
var TOP_DICT_META = [{
name: 'version',
op: 0,
type: 'SID'
}, {
name: 'notice',
op: 1,
type: 'SID'
}, {
name: 'copyright',
op: 1200,
type: 'SID'
}, {
name: 'fullName',
op: 2,
type: 'SID'
}, {
name: 'familyName',
op: 3,
type: 'SID'
}, {
name: 'weight',
op: 4,
type: 'SID'
}, {
name: 'isFixedPitch',
op: 1201,
type: 'number',
value: 0
}, {
name: 'italicAngle',
op: 1202,
type: 'number',
value: 0
}, {
name: 'underlinePosition',
op: 1203,
type: 'number',
value: -100
}, {
name: 'underlineThickness',
op: 1204,
type: 'number',
value: 50
}, {
name: 'paintType',
op: 1205,
type: 'number',
value: 0
}, {
name: 'charstringType',
op: 1206,
type: 'number',
value: 2
}, {
name: 'fontMatrix',
op: 1207,
type: ['real', 'real', 'real', 'real', 'real', 'real'],
value: [0.001, 0, 0, 0.001, 0, 0]
}, {
name: 'uniqueId',
op: 13,
type: 'number'
}, {
name: 'fontBBox',
op: 5,
type: ['number', 'number', 'number', 'number'],
value: [0, 0, 0, 0]
}, {
name: 'strokeWidth',
op: 1208,
type: 'number',
value: 0
}, {
name: 'xuid',
op: 14,
type: [],
value: null
}, {
name: 'charset',
op: 15,
type: 'offset',
value: 0
}, {
name: 'encoding',
op: 16,
type: 'offset',
value: 0
}, {
name: 'charStrings',
op: 17,
type: 'offset',
value: 0
}, {
name: 'private',
op: 18,
type: ['number', 'offset'],
value: [0, 0]
}];
var PRIVATE_DICT_META = [{
name: 'subrs',
op: 19,
type: 'offset',
value: 0
}, {
name: 'defaultWidthX',
op: 20,
type: 'number',
value: 0
}, {
name: 'nominalWidthX',
op: 21,
type: 'number',
value: 0
}];
function entriesToObject(entries) {
var hash = {};
for (var i = 0, l = entries.length; i < l; i++) {
var key = entries[i][0];
if (undefined !== hash[key]) {
console.warn('dict already has key:' + key);
continue;
}
var values = entries[i][1];
hash[key] = values.length === 1 ? values[0] : values;
}
return hash;
}
/* eslint-disable no-constant-condition */
function parseFloatOperand(reader) {
var s = '';
var eof = 15;
var lookup = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', 'E', 'E-', null, '-'];
while (true) {
var b = reader.readUint8();
var n1 = b >> 4;
var n2 = b & 15;
if (n1 === eof) {
break;
}
s += lookup[n1];
if (n2 === eof) {
break;
}
s += lookup[n2];
}
return parseFloat(s);
}
/* eslint-enable no-constant-condition */
/**
* 解析cff字典数据
*
* @param {Reader} reader 读取器
* @param {number} b0 操作码
* @return {number} 数据
*/
function parseOperand(reader, b0) {
var b1;
var b2;
var b3;
var b4;
if (b0 === 28) {
b1 = reader.readUint8();
b2 = reader.readUint8();
return b1 << 8 | b2;
}
if (b0 === 29) {
b1 = reader.readUint8();
b2 = reader.readUint8();
b3 = reader.readUint8();
b4 = reader.readUint8();
return b1 << 24 | b2 << 16 | b3 << 8 | b4;
}
if (b0 === 30) {
return parseFloatOperand(reader);
}
if (b0 >= 32 && b0 <= 246) {
return b0 - 139;
}
if (b0 >= 247 && b0 <= 250) {
b1 = reader.readUint8();
return (b0 - 247) * 256 + b1 + 108;
}
if (b0 >= 251 && b0 <= 254) {
b1 = reader.readUint8();
return -(b0 - 251) * 256 - b1 - 108;
}
throw new Error('invalid b0 ' + b0 + ',at:' + reader.offset);
}
/**
* 解析字典值
*
* @param {Object} dict 字典数据
* @param {Array} meta 元数据
* @param {Object} strings cff字符串字典
* @return {Object} 解析后数据
*/
function interpretDict(dict, meta, strings) {
var newDict = {};
// Because we also want to include missing values, we start out from the meta list
// and lookup values in the dict.
for (var i = 0, l = meta.length; i < l; i++) {
var m = meta[i];
var value = dict[m.op];
if (value === undefined) {
value = m.value !== undefined ? m.value : null;
}
if (m.type === 'SID') {
value = (0, _getCFFString.default)(strings, value);
}
newDict[m.name] = value;
}
return newDict;
}
/**
* 解析cff dict字典
*
* @param {Reader} reader 读取器
* @param {number} offset 起始偏移
* @param {number} length 大小
* @return {Object} 配置
*/
function parseCFFDict(reader, offset, length) {
if (null != offset) {
reader.seek(offset);
}
var entries = [];
var operands = [];
var lastOffset = reader.offset + (null != length ? length : reader.length);
while (reader.offset < lastOffset) {
var op = reader.readUint8();
// The first byte for each dict item distinguishes between operator (key) and operand (value).
// Values <= 21 are operators.
if (op <= 21) {
// Two-byte operators have an initial escape byte of 12.
if (op === 12) {
op = 1200 + reader.readUint8();
}
entries.push([op, operands]);
operands = [];
} else {
// Since the operands (values) come before the operators (keys), we store all operands in a list
// until we encounter an operator.
operands.push(parseOperand(reader, op));
}
}
return entriesToObject(entries);
}
/**
* 解析cff top字典
*
* @param {Reader} reader 读取器
* @param {number} start 开始offset
* @param {number} length 大小
* @param {Object} strings 字符串集合
* @return {Object} 字典数据
*/
function parseTopDict(reader, start, length, strings) {
var dict = parseCFFDict(reader, start || 0, length || reader.length);
return interpretDict(dict, TOP_DICT_META, strings);
}
/**
* 解析cff私有字典
*
* @param {Reader} reader 读取器
* @param {number} start 开始offset
* @param {number} length 大小
* @param {Object} strings 字符串集合
* @return {Object} 字典数据
*/
function parsePrivateDict(reader, start, length, strings) {
var dict = parseCFFDict(reader, start || 0, length || reader.length);
return interpretDict(dict, PRIVATE_DICT_META, strings);
}
var _default = exports.default = {
parseTopDict: parseTopDict,
parsePrivateDict: parsePrivateDict
};

View File

@ -0,0 +1,49 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = parseCFFEncoding;
/**
* @file 解析cff编码
* @author mengke01(kekee000@gmail.com)
*/
/**
* 解析cff encoding数据
* See Adobe TN #5176 chapter 12, "Encodings".
*
* @param {Reader} reader 读取器
* @param {number=} start 偏移
* @return {Object} 编码表
*/
function parseCFFEncoding(reader, start) {
if (null != start) {
reader.seek(start);
}
var i;
var code;
var encoding = {};
var format = reader.readUint8();
if (format === 0) {
var nCodes = reader.readUint8();
for (i = 0; i < nCodes; i += 1) {
code = reader.readUint8();
encoding[code] = i;
}
} else if (format === 1) {
var nRanges = reader.readUint8();
code = 1;
for (i = 0; i < nRanges; i += 1) {
var first = reader.readUint8();
var nLeft = reader.readUint8();
for (var j = first; j <= first + nLeft; j += 1) {
encoding[j] = code;
code += 1;
}
}
} else {
console.warn('unknown encoding format:' + format);
}
return encoding;
}

View File

@ -0,0 +1,508 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = parseCFFCharstring;
/**
* @file 解析cff字形
* @author mengke01(kekee000@gmail.com)
*/
/**
* 解析cff字形返回直线和三次bezier曲线点数组
*
* @param {Array} code 操作码
* @param {Object} font 相关联的font对象
* @param {number} index glyf索引
* @return {Object} glyf对象
*/
function parseCFFCharstring(code, font, index) {
var c1x;
var c1y;
var c2x;
var c2y;
var contours = [];
var contour = [];
var stack = [];
var glyfs = [];
var nStems = 0;
var haveWidth = false;
var width = font.defaultWidthX;
var open = false;
var x = 0;
var y = 0;
function lineTo(x, y) {
contour.push({
onCurve: true,
x: x,
y: y
});
}
function curveTo(c1x, c1y, c2x, c2y, x, y) {
contour.push({
x: c1x,
y: c1y
});
contour.push({
x: c2x,
y: c2y
});
contour.push({
onCurve: true,
x: x,
y: y
});
}
function newContour(x, y) {
if (open) {
contours.push(contour);
}
contour = [];
lineTo(x, y);
open = true;
}
function parseStems() {
// The number of stem operators on the stack is always even.
// If the value is uneven, that means a width is specified.
var hasWidthArg = stack.length % 2 !== 0;
if (hasWidthArg && !haveWidth) {
width = stack.shift() + font.nominalWidthX;
}
nStems += stack.length >> 1;
stack.length = 0;
haveWidth = true;
}
function parse(code) {
var b1;
var b2;
var b3;
var b4;
var codeIndex;
var subrCode;
var jpx;
var jpy;
var c3x;
var c3y;
var c4x;
var c4y;
var i = 0;
while (i < code.length) {
var v = code[i];
i += 1;
switch (v) {
case 1:
// hstem
parseStems();
break;
case 3:
// vstem
parseStems();
break;
case 4:
// vmoveto
if (stack.length > 1 && !haveWidth) {
width = stack.shift() + font.nominalWidthX;
haveWidth = true;
}
y += stack.pop();
newContour(x, y);
break;
case 5:
// rlineto
while (stack.length > 0) {
x += stack.shift();
y += stack.shift();
lineTo(x, y);
}
break;
case 6:
// hlineto
while (stack.length > 0) {
x += stack.shift();
lineTo(x, y);
if (stack.length === 0) {
break;
}
y += stack.shift();
lineTo(x, y);
}
break;
case 7:
// vlineto
while (stack.length > 0) {
y += stack.shift();
lineTo(x, y);
if (stack.length === 0) {
break;
}
x += stack.shift();
lineTo(x, y);
}
break;
case 8:
// rrcurveto
while (stack.length > 0) {
c1x = x + stack.shift();
c1y = y + stack.shift();
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
x = c2x + stack.shift();
y = c2y + stack.shift();
curveTo(c1x, c1y, c2x, c2y, x, y);
}
break;
case 10:
// callsubr
codeIndex = stack.pop() + font.subrsBias;
subrCode = font.subrs[codeIndex];
if (subrCode) {
parse(subrCode);
}
break;
case 11:
// return
return;
case 12:
// flex operators
v = code[i];
i += 1;
switch (v) {
case 35:
// flex
// |- dx1 dy1 dx2 dy2 dx3 dy3 dx4 dy4 dx5 dy5 dx6 dy6 fd flex (12 35) |-
c1x = x + stack.shift(); // dx1
c1y = y + stack.shift(); // dy1
c2x = c1x + stack.shift(); // dx2
c2y = c1y + stack.shift(); // dy2
jpx = c2x + stack.shift(); // dx3
jpy = c2y + stack.shift(); // dy3
c3x = jpx + stack.shift(); // dx4
c3y = jpy + stack.shift(); // dy4
c4x = c3x + stack.shift(); // dx5
c4y = c3y + stack.shift(); // dy5
x = c4x + stack.shift(); // dx6
y = c4y + stack.shift(); // dy6
stack.shift(); // flex depth
curveTo(c1x, c1y, c2x, c2y, jpx, jpy);
curveTo(c3x, c3y, c4x, c4y, x, y);
break;
case 34:
// hflex
// |- dx1 dx2 dy2 dx3 dx4 dx5 dx6 hflex (12 34) |-
c1x = x + stack.shift(); // dx1
c1y = y; // dy1
c2x = c1x + stack.shift(); // dx2
c2y = c1y + stack.shift(); // dy2
jpx = c2x + stack.shift(); // dx3
jpy = c2y; // dy3
c3x = jpx + stack.shift(); // dx4
c3y = c2y; // dy4
c4x = c3x + stack.shift(); // dx5
c4y = y; // dy5
x = c4x + stack.shift(); // dx6
curveTo(c1x, c1y, c2x, c2y, jpx, jpy);
curveTo(c3x, c3y, c4x, c4y, x, y);
break;
case 36:
// hflex1
// |- dx1 dy1 dx2 dy2 dx3 dx4 dx5 dy5 dx6 hflex1 (12 36) |-
c1x = x + stack.shift(); // dx1
c1y = y + stack.shift(); // dy1
c2x = c1x + stack.shift(); // dx2
c2y = c1y + stack.shift(); // dy2
jpx = c2x + stack.shift(); // dx3
jpy = c2y; // dy3
c3x = jpx + stack.shift(); // dx4
c3y = c2y; // dy4
c4x = c3x + stack.shift(); // dx5
c4y = c3y + stack.shift(); // dy5
x = c4x + stack.shift(); // dx6
curveTo(c1x, c1y, c2x, c2y, jpx, jpy);
curveTo(c3x, c3y, c4x, c4y, x, y);
break;
case 37:
// flex1
// |- dx1 dy1 dx2 dy2 dx3 dy3 dx4 dy4 dx5 dy5 d6 flex1 (12 37) |-
c1x = x + stack.shift(); // dx1
c1y = y + stack.shift(); // dy1
c2x = c1x + stack.shift(); // dx2
c2y = c1y + stack.shift(); // dy2
jpx = c2x + stack.shift(); // dx3
jpy = c2y + stack.shift(); // dy3
c3x = jpx + stack.shift(); // dx4
c3y = jpy + stack.shift(); // dy4
c4x = c3x + stack.shift(); // dx5
c4y = c3y + stack.shift(); // dy5
if (Math.abs(c4x - x) > Math.abs(c4y - y)) {
x = c4x + stack.shift();
} else {
y = c4y + stack.shift();
}
curveTo(c1x, c1y, c2x, c2y, jpx, jpy);
curveTo(c3x, c3y, c4x, c4y, x, y);
break;
default:
console.warn('Glyph ' + index + ': unknown operator ' + (1200 + v));
stack.length = 0;
}
break;
case 14:
// endchar
if (stack.length === 1 && !haveWidth) {
width = stack.shift() + font.nominalWidthX;
haveWidth = true;
} else if (stack.length === 4) {
glyfs[1] = {
glyphIndex: font.charset.indexOf(font.encoding[stack.pop()]),
transform: {
a: 1,
b: 0,
c: 0,
d: 1,
e: 0,
f: 0
}
};
glyfs[0] = {
glyphIndex: font.charset.indexOf(font.encoding[stack.pop()]),
transform: {
a: 1,
b: 0,
c: 0,
d: 1,
e: 0,
f: 0
}
};
glyfs[1].transform.f = stack.pop();
glyfs[1].transform.e = stack.pop();
} else if (stack.length === 5) {
if (!haveWidth) {
width = stack.shift() + font.nominalWidthX;
}
haveWidth = true;
glyfs[1] = {
glyphIndex: font.charset.indexOf(font.encoding[stack.pop()]),
transform: {
a: 1,
b: 0,
c: 0,
d: 1,
e: 0,
f: 0
}
};
glyfs[0] = {
glyphIndex: font.charset.indexOf(font.encoding[stack.pop()]),
transform: {
a: 1,
b: 0,
c: 0,
d: 1,
e: 0,
f: 0
}
};
glyfs[1].transform.f = stack.pop();
glyfs[1].transform.e = stack.pop();
}
if (open) {
contours.push(contour);
open = false;
}
break;
case 18:
// hstemhm
parseStems();
break;
case 19: // hintmask
case 20:
// cntrmask
parseStems();
i += nStems + 7 >> 3;
break;
case 21:
// rmoveto
if (stack.length > 2 && !haveWidth) {
width = stack.shift() + font.nominalWidthX;
haveWidth = true;
}
y += stack.pop();
x += stack.pop();
newContour(x, y);
break;
case 22:
// hmoveto
if (stack.length > 1 && !haveWidth) {
width = stack.shift() + font.nominalWidthX;
haveWidth = true;
}
x += stack.pop();
newContour(x, y);
break;
case 23:
// vstemhm
parseStems();
break;
case 24:
// rcurveline
while (stack.length > 2) {
c1x = x + stack.shift();
c1y = y + stack.shift();
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
x = c2x + stack.shift();
y = c2y + stack.shift();
curveTo(c1x, c1y, c2x, c2y, x, y);
}
x += stack.shift();
y += stack.shift();
lineTo(x, y);
break;
case 25:
// rlinecurve
while (stack.length > 6) {
x += stack.shift();
y += stack.shift();
lineTo(x, y);
}
c1x = x + stack.shift();
c1y = y + stack.shift();
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
x = c2x + stack.shift();
y = c2y + stack.shift();
curveTo(c1x, c1y, c2x, c2y, x, y);
break;
case 26:
// vvcurveto
if (stack.length % 2) {
x += stack.shift();
}
while (stack.length > 0) {
c1x = x;
c1y = y + stack.shift();
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
x = c2x;
y = c2y + stack.shift();
curveTo(c1x, c1y, c2x, c2y, x, y);
}
break;
case 27:
// hhcurveto
if (stack.length % 2) {
y += stack.shift();
}
while (stack.length > 0) {
c1x = x + stack.shift();
c1y = y;
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
x = c2x + stack.shift();
y = c2y;
curveTo(c1x, c1y, c2x, c2y, x, y);
}
break;
case 28:
// shortint
b1 = code[i];
b2 = code[i + 1];
stack.push((b1 << 24 | b2 << 16) >> 16);
i += 2;
break;
case 29:
// callgsubr
codeIndex = stack.pop() + font.gsubrsBias;
subrCode = font.gsubrs[codeIndex];
if (subrCode) {
parse(subrCode);
}
break;
case 30:
// vhcurveto
while (stack.length > 0) {
c1x = x;
c1y = y + stack.shift();
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
x = c2x + stack.shift();
y = c2y + (stack.length === 1 ? stack.shift() : 0);
curveTo(c1x, c1y, c2x, c2y, x, y);
if (stack.length === 0) {
break;
}
c1x = x + stack.shift();
c1y = y;
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
y = c2y + stack.shift();
x = c2x + (stack.length === 1 ? stack.shift() : 0);
curveTo(c1x, c1y, c2x, c2y, x, y);
}
break;
case 31:
// hvcurveto
while (stack.length > 0) {
c1x = x + stack.shift();
c1y = y;
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
y = c2y + stack.shift();
x = c2x + (stack.length === 1 ? stack.shift() : 0);
curveTo(c1x, c1y, c2x, c2y, x, y);
if (stack.length === 0) {
break;
}
c1x = x;
c1y = y + stack.shift();
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
x = c2x + stack.shift();
y = c2y + (stack.length === 1 ? stack.shift() : 0);
curveTo(c1x, c1y, c2x, c2y, x, y);
}
break;
default:
if (v < 32) {
console.warn('Glyph ' + index + ': unknown operator ' + v);
} else if (v < 247) {
stack.push(v - 139);
} else if (v < 251) {
b1 = code[i];
i += 1;
stack.push((v - 247) * 256 + b1 + 108);
} else if (v < 255) {
b1 = code[i];
i += 1;
stack.push(-(v - 251) * 256 - b1 - 108);
} else {
b1 = code[i];
b2 = code[i + 1];
b3 = code[i + 2];
b4 = code[i + 3];
i += 4;
stack.push((b1 << 24 | b2 << 16 | b3 << 8 | b4) / 65536);
}
}
}
}
parse(code);
var glyf = {
// 移除重复的起点和终点
contours: contours.map(function (contour) {
var last = contour.length - 1;
if (contour[0].x === contour[last].x && contour[0].y === contour[last].y) {
contour.splice(last, 1);
}
return contour;
}),
advanceWidth: width
};
if (glyfs.length) {
glyf.compound = true;
glyf.glyfs = glyfs;
}
return glyf;
}

View File

@ -0,0 +1,23 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _table = _interopRequireDefault(require("./table"));
var _parse = _interopRequireDefault(require("./cmap/parse"));
var _write = _interopRequireDefault(require("./cmap/write"));
var _sizeof = _interopRequireDefault(require("./cmap/sizeof"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file cmap
* @author mengke01(kekee000@gmail.com)
*
* @see
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6cmap.html
*/
var _default = exports.default = _table.default.create('cmap', [], {
write: _write.default,
read: _parse.default,
size: _sizeof.default
});

View File

@ -0,0 +1,230 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = parse;
var _readWindowsAllCodes = _interopRequireDefault(require("../../util/readWindowsAllCodes"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file 解析cmap表
* @author mengke01(kekee000@gmail.com)
*/
/**
* 读取cmap子表
*
* @param {Reader} reader Reader对象
* @param {Object} ttf ttf对象
* @param {Object} subTable 子表对象
* @param {number} cmapOffset 子表的偏移
*/
function readSubTable(reader, ttf, subTable, cmapOffset) {
var i;
var l;
var glyphIdArray;
var startOffset = cmapOffset + subTable.offset;
var glyphCount;
subTable.format = reader.readUint16(startOffset);
// 0256 紧凑排列
if (subTable.format === 0) {
var format0 = subTable;
// 跳过format字段
format0.length = reader.readUint16();
format0.language = reader.readUint16();
glyphIdArray = [];
for (i = 0, l = format0.length - 6; i < l; i++) {
glyphIdArray.push(reader.readUint8());
}
format0.glyphIdArray = glyphIdArray;
} else if (subTable.format === 2) {
var format2 = subTable;
// 跳过format字段
format2.length = reader.readUint16();
format2.language = reader.readUint16();
var subHeadKeys = [];
var maxSubHeadKey = 0; // 最大索引
var maxPos = -1; // 最大位置
for (var _i = 0, _l = 256; _i < _l; _i++) {
subHeadKeys[_i] = reader.readUint16() / 8;
if (subHeadKeys[_i] > maxSubHeadKey) {
maxSubHeadKey = subHeadKeys[_i];
maxPos = _i;
}
}
var subHeads = [];
for (i = 0; i <= maxSubHeadKey; i++) {
subHeads[i] = {
firstCode: reader.readUint16(),
entryCount: reader.readUint16(),
idDelta: reader.readUint16(),
idRangeOffset: (reader.readUint16() - (maxSubHeadKey - i) * 8 - 2) / 2
};
}
glyphCount = (startOffset + format2.length - reader.offset) / 2;
var glyphs = [];
for (i = 0; i < glyphCount; i++) {
glyphs[i] = reader.readUint16();
}
format2.subHeadKeys = subHeadKeys;
format2.maxPos = maxPos;
format2.subHeads = subHeads;
format2.glyphs = glyphs;
}
// 双字节编码,非紧凑排列
else if (subTable.format === 4) {
var format4 = subTable;
// 跳过format字段
format4.length = reader.readUint16();
format4.language = reader.readUint16();
format4.segCountX2 = reader.readUint16();
format4.searchRange = reader.readUint16();
format4.entrySelector = reader.readUint16();
format4.rangeShift = reader.readUint16();
var segCount = format4.segCountX2 / 2;
// end code
var endCode = [];
for (i = 0; i < segCount; ++i) {
endCode.push(reader.readUint16());
}
format4.endCode = endCode;
format4.reservedPad = reader.readUint16();
// start code
var startCode = [];
for (i = 0; i < segCount; ++i) {
startCode.push(reader.readUint16());
}
format4.startCode = startCode;
// idDelta
var idDelta = [];
for (i = 0; i < segCount; ++i) {
idDelta.push(reader.readUint16());
}
format4.idDelta = idDelta;
format4.idRangeOffsetOffset = reader.offset;
// idRangeOffset
var idRangeOffset = [];
for (i = 0; i < segCount; ++i) {
idRangeOffset.push(reader.readUint16());
}
format4.idRangeOffset = idRangeOffset;
// 总长度 - glyphIdArray起始偏移/2
glyphCount = (format4.length - (reader.offset - startOffset)) / 2;
// 记录array offset
format4.glyphIdArrayOffset = reader.offset;
// glyphIdArray
glyphIdArray = [];
for (i = 0; i < glyphCount; ++i) {
glyphIdArray.push(reader.readUint16());
}
format4.glyphIdArray = glyphIdArray;
} else if (subTable.format === 6) {
var format6 = subTable;
format6.length = reader.readUint16();
format6.language = reader.readUint16();
format6.firstCode = reader.readUint16();
format6.entryCount = reader.readUint16();
// 记录array offset
format6.glyphIdArrayOffset = reader.offset;
var glyphIndexArray = [];
var entryCount = format6.entryCount;
// 读取字符分组
for (i = 0; i < entryCount; ++i) {
glyphIndexArray.push(reader.readUint16());
}
format6.glyphIdArray = glyphIndexArray;
}
// defines segments for sparse representation in 4-byte character space
else if (subTable.format === 12) {
var format12 = subTable;
format12.reserved = reader.readUint16();
format12.length = reader.readUint32();
format12.language = reader.readUint32();
format12.nGroups = reader.readUint32();
var groups = [];
var nGroups = format12.nGroups;
// 读取字符分组
for (i = 0; i < nGroups; ++i) {
var group = {};
group.start = reader.readUint32();
group.end = reader.readUint32();
group.startId = reader.readUint32();
groups.push(group);
}
format12.groups = groups;
}
// format 14
else if (subTable.format === 14) {
var format14 = subTable;
format14.length = reader.readUint32();
var numVarSelectorRecords = reader.readUint32();
var _groups = [];
var offset = reader.offset;
for (var _i2 = 0; _i2 < numVarSelectorRecords; _i2++) {
var varSelector = reader.readUint24(offset);
var defaultUVSOffset = reader.readUint32(offset + 3);
var nonDefaultUVSOffset = reader.readUint32(offset + 7);
offset += 11;
if (defaultUVSOffset) {
var numUnicodeValueRanges = reader.readUint32(startOffset + defaultUVSOffset);
for (var j = 0; j < numUnicodeValueRanges; j++) {
var startUnicode = reader.readUint24();
var additionalCount = reader.readUint8();
_groups.push({
start: startUnicode,
end: startUnicode + additionalCount,
varSelector: varSelector
});
}
}
if (nonDefaultUVSOffset) {
var numUVSMappings = reader.readUint32(startOffset + nonDefaultUVSOffset);
for (var _j = 0; _j < numUVSMappings; _j++) {
var unicode = reader.readUint24();
var glyphId = reader.readUint16();
_groups.push({
unicode: unicode,
glyphId: glyphId,
varSelector: varSelector
});
}
}
}
format14.groups = _groups;
} else {
console.warn('not support cmap format:' + subTable.format);
}
}
function parse(reader, ttf) {
var tcmap = {};
// eslint-disable-next-line no-invalid-this
var cmapOffset = this.offset;
reader.seek(cmapOffset);
tcmap.version = reader.readUint16(); // 编码方式
var numberSubtables = tcmap.numberSubtables = reader.readUint16(); // 表个数
var subTables = tcmap.tables = []; // 名字表
var offset = reader.offset;
// 使用offset读取以便于查找
for (var i = 0, l = numberSubtables; i < l; i++) {
var subTable = {};
subTable.platformID = reader.readUint16(offset);
subTable.encodingID = reader.readUint16(offset + 2);
subTable.offset = reader.readUint32(offset + 4);
readSubTable(reader, ttf, subTable, cmapOffset);
subTables.push(subTable);
offset += 8;
}
var cmap = (0, _readWindowsAllCodes.default)(subTables, ttf);
return cmap;
}

View File

@ -0,0 +1,138 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = sizeof;
/**
* @file 获取cmap表的大小
* @author mengke01(kekee000@gmail.com)
*/
/**
* 获取format4 delta值
* Delta is saved in signed int in cmap format 4 subtable,
* but can be in -0xFFFF..0 interval.
* -0x10000..-0x7FFF values are stored with offset.
*
* @param {number} delta delta值
* @return {number} delta值
*/
function encodeDelta(delta) {
return delta > 0x7FFF ? delta - 0x10000 : delta < -0x7FFF ? delta + 0x10000 : delta;
}
/**
* 根据bound获取glyf segment
*
* @param {Array} glyfUnicodes glyf编码集合
* @param {number} bound 编码范围
* @return {Array} 码表
*/
function getSegments(glyfUnicodes, bound) {
var prevGlyph = null;
var result = [];
var segment = {};
glyfUnicodes.forEach(function (glyph) {
if (bound === undefined || glyph.unicode <= bound) {
// 初始化编码头部这里unicode和graph id 都必须连续
if (prevGlyph === null || glyph.unicode !== prevGlyph.unicode + 1 || glyph.id !== prevGlyph.id + 1) {
if (prevGlyph !== null) {
segment.end = prevGlyph.unicode;
result.push(segment);
segment = {
start: glyph.unicode,
startId: glyph.id,
delta: encodeDelta(glyph.id - glyph.unicode)
};
} else {
segment.start = glyph.unicode;
segment.startId = glyph.id;
segment.delta = encodeDelta(glyph.id - glyph.unicode);
}
}
prevGlyph = glyph;
}
});
// need to finish the last segment
if (prevGlyph !== null) {
segment.end = prevGlyph.unicode;
result.push(segment);
}
// 返回编码范围
return result;
}
/**
* 获取format0编码集合
*
* @param {Array} glyfUnicodes glyf编码集合
* @return {Array} 码表
*/
function getFormat0Segment(glyfUnicodes) {
var unicodes = [];
glyfUnicodes.forEach(function (u) {
if (u.unicode !== undefined && u.unicode < 256) {
unicodes.push([u.unicode, u.id]);
}
});
// 按编码排序
unicodes.sort(function (a, b) {
return a[0] - b[0];
});
return unicodes;
}
/**
* 对cmap数据进行预处理获取大小
*
* @param {Object} ttf ttf对象
* @return {number} 大小
*/
function sizeof(ttf) {
ttf.support.cmap = {};
var glyfUnicodes = [];
ttf.glyf.forEach(function (glyph, index) {
var unicodes = glyph.unicode;
if (typeof glyph.unicode === 'number') {
unicodes = [glyph.unicode];
}
if (unicodes && unicodes.length) {
unicodes.forEach(function (unicode) {
glyfUnicodes.push({
unicode: unicode,
id: unicode !== 0xFFFF ? index : 0
});
});
}
});
glyfUnicodes = glyfUnicodes.sort(function (a, b) {
return a.unicode - b.unicode;
});
ttf.support.cmap.unicodes = glyfUnicodes;
var unicodes2Bytes = glyfUnicodes;
ttf.support.cmap.format4Segments = getSegments(unicodes2Bytes, 0xFFFF);
ttf.support.cmap.format4Size = 24 + ttf.support.cmap.format4Segments.length * 8;
ttf.support.cmap.format0Segments = getFormat0Segment(glyfUnicodes);
ttf.support.cmap.format0Size = 262;
// we need subtable 12 only if found unicodes with > 2 bytes.
var hasGLyphsOver2Bytes = unicodes2Bytes.some(function (glyph) {
return glyph.unicode > 0xFFFF;
});
if (hasGLyphsOver2Bytes) {
ttf.support.cmap.hasGLyphsOver2Bytes = hasGLyphsOver2Bytes;
var unicodes4Bytes = glyfUnicodes;
ttf.support.cmap.format12Segments = getSegments(unicodes4Bytes);
ttf.support.cmap.format12Size = 16 + ttf.support.cmap.format12Segments.length * 12;
}
var size = 4 + (hasGLyphsOver2Bytes ? 32 : 24) // cmap header
+ ttf.support.cmap.format0Size // format 0
+ ttf.support.cmap.format4Size // format 4
+ (hasGLyphsOver2Bytes ? ttf.support.cmap.format12Size : 0); // format 12
return size;
}

View File

@ -0,0 +1,164 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = write;
/**
* @file 写cmap表
* @author mengke01(kekee000@gmail.com)
*/
/**
* 创建`子表0`
*
* @param {Writer} writer 写对象
* @param {Array} unicodes unicodes列表
* @return {Writer}
*/
function writeSubTable0(writer, unicodes) {
writer.writeUint16(0); // format
writer.writeUint16(262); // length
writer.writeUint16(0); // language
// Array of unicodes 0..255
var i = -1;
var unicode;
while (unicode = unicodes.shift()) {
while (++i < unicode[0]) {
writer.writeUint8(0);
}
writer.writeUint8(unicode[1]);
i = unicode[0];
}
while (++i < 256) {
writer.writeUint8(0);
}
return writer;
}
/**
* 创建`子表4`
*
* @param {Writer} writer 写对象
* @param {Array} segments 分块编码列表
* @return {Writer}
*/
function writeSubTable4(writer, segments) {
writer.writeUint16(4); // format
writer.writeUint16(24 + segments.length * 8); // length
writer.writeUint16(0); // language
var segCount = segments.length + 1;
var maxExponent = Math.floor(Math.log(segCount) / Math.LN2);
var searchRange = 2 * Math.pow(2, maxExponent);
writer.writeUint16(segCount * 2); // segCountX2
writer.writeUint16(searchRange); // searchRange
writer.writeUint16(maxExponent); // entrySelector
writer.writeUint16(2 * segCount - searchRange); // rangeShift
// end list
segments.forEach(function (segment) {
writer.writeUint16(segment.end);
});
writer.writeUint16(0xFFFF); // end code
writer.writeUint16(0); // reservedPad
// start list
segments.forEach(function (segment) {
writer.writeUint16(segment.start);
});
writer.writeUint16(0xFFFF); // start code
// id delta
segments.forEach(function (segment) {
writer.writeUint16(segment.delta);
});
writer.writeUint16(1);
// Array of range offsets, it doesn't matter when deltas present
for (var i = 0, l = segments.length; i < l; i++) {
writer.writeUint16(0);
}
writer.writeUint16(0); // rangeOffsetArray should be finished with 0
return writer;
}
/**
* 创建`子表12`
*
* @param {Writer} writer 写对象
* @param {Array} segments 分块编码列表
* @return {Writer}
*/
function writeSubTable12(writer, segments) {
writer.writeUint16(12); // format
writer.writeUint16(0); // reserved
writer.writeUint32(16 + segments.length * 12); // length
writer.writeUint32(0); // language
writer.writeUint32(segments.length); // nGroups
segments.forEach(function (segment) {
writer.writeUint32(segment.start);
writer.writeUint32(segment.end);
writer.writeUint32(segment.startId);
});
return writer;
}
/**
* 写subtableheader
*
* @param {Writer} writer Writer对象
* @param {number} platform 平台
* @param {number} encoding 编码
* @param {number} offset 偏移
* @return {Writer}
*/
function writeSubTableHeader(writer, platform, encoding, offset) {
writer.writeUint16(platform); // platform
writer.writeUint16(encoding); // encoding
writer.writeUint32(offset); // offset
return writer;
}
/**
* 写cmap表数据
*
* @param {Object} writer 写入器
* @param {Object} ttf ttf对象
* @return {Object} 写入器
*/
function write(writer, ttf) {
var hasGLyphsOver2Bytes = ttf.support.cmap.hasGLyphsOver2Bytes;
// write table header.
writer.writeUint16(0); // version
writer.writeUint16(hasGLyphsOver2Bytes ? 4 : 3); // count
// header size
var subTableOffset = 4 + (hasGLyphsOver2Bytes ? 32 : 24);
var format4Size = ttf.support.cmap.format4Size;
var format0Size = ttf.support.cmap.format0Size;
// subtable 4, unicode
writeSubTableHeader(writer, 0, 3, subTableOffset);
// subtable 0, mac standard
writeSubTableHeader(writer, 1, 0, subTableOffset + format4Size);
// subtable 4, windows standard
writeSubTableHeader(writer, 3, 1, subTableOffset);
if (hasGLyphsOver2Bytes) {
writeSubTableHeader(writer, 3, 10, subTableOffset + format4Size + format0Size);
}
// write tables, order of table seem to be magic, it is taken from TTX tool
writeSubTable4(writer, ttf.support.cmap.format4Segments);
writeSubTable0(writer, ttf.support.cmap.format0Segments);
if (hasGLyphsOver2Bytes) {
writeSubTable12(writer, ttf.support.cmap.format12Segments);
}
return writer;
}

View File

@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _table = _interopRequireDefault(require("./table"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file cvt表
* @author mengke01(kekee000@gmail.com)
*
* @reference: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6cvt.html
*/
var _default = exports.default = _table.default.create('cvt', [], {
read: function read(reader, ttf) {
var length = ttf.tables.cvt.length;
return reader.readBytes(this.offset, length);
},
write: function write(writer, ttf) {
if (ttf.cvt) {
writer.writeBytes(ttf.cvt, ttf.cvt.length);
}
},
size: function size(ttf) {
return ttf.cvt ? ttf.cvt.length : 0;
}
});

View File

@ -0,0 +1,44 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _table = _interopRequireDefault(require("./table"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file directory , 读取和写入ttf表索引
* @author mengke01(kekee000@gmail.com)
*
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6.html
*/
var _default = exports.default = _table.default.create('directory', [], {
read: function read(reader, ttf) {
var tables = {};
var numTables = ttf.numTables;
var offset = this.offset;
for (var i = offset, l = numTables * 16; i < l; i += 16) {
var name = reader.readString(i, 4).trim();
tables[name] = {
name: name,
checkSum: reader.readUint32(i + 4),
offset: reader.readUint32(i + 8),
length: reader.readUint32(i + 12)
};
}
return tables;
},
write: function write(writer, ttf) {
var tables = ttf.support.tables;
for (var i = 0, l = tables.length; i < l; i++) {
writer.writeString((tables[i].name + ' ').slice(0, 4));
writer.writeUint32(tables[i].checkSum);
writer.writeUint32(tables[i].offset);
writer.writeUint32(tables[i].length);
}
return writer;
},
size: function size(ttf) {
return ttf.numTables * 16;
}
});

View File

@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _table = _interopRequireDefault(require("./table"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file fpgm
* @author mengke01(kekee000@gmail.com)
*
* reference: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6fpgm.html
*/
var _default = exports.default = _table.default.create('fpgm', [], {
read: function read(reader, ttf) {
var length = ttf.tables.fpgm.length;
return reader.readBytes(this.offset, length);
},
write: function write(writer, ttf) {
if (ttf.fpgm) {
writer.writeBytes(ttf.fpgm, ttf.fpgm.length);
}
},
size: function size(ttf) {
return ttf.fpgm ? ttf.fpgm.length : 0;
}
});

View File

@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _table = _interopRequireDefault(require("./table"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file gasp
* 对于需要hinting的字号需要这个表否则会导致错误
* @author mengke01(kekee000@gmail.com)
* reference: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6gasp.html
*/
var _default = exports.default = _table.default.create('gasp', [], {
read: function read(reader, ttf) {
var length = ttf.tables.gasp.length;
return reader.readBytes(this.offset, length);
},
write: function write(writer, ttf) {
if (ttf.gasp) {
writer.writeBytes(ttf.gasp, ttf.gasp.length);
}
},
size: function size(ttf) {
return ttf.gasp ? ttf.gasp.length : 0;
}
});

View File

@ -0,0 +1,102 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _table = _interopRequireDefault(require("./table"));
var _parse = _interopRequireDefault(require("./glyf/parse"));
var _write = _interopRequireDefault(require("./glyf/write"));
var _sizeof = _interopRequireDefault(require("./glyf/sizeof"));
var _lang = require("../../common/lang");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file glyf表
* @author mengke01(kekee000@gmail.com)
*
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6glyf.html
*/
var _default = exports.default = _table.default.create('glyf', [], {
read: function read(reader, ttf) {
var startOffset = this.offset;
var loca = ttf.loca;
var numGlyphs = ttf.maxp.numGlyphs;
var glyphs = [];
reader.seek(startOffset);
// subset
var subset = ttf.readOptions.subset;
if (subset && subset.length > 0) {
var subsetMap = {
0: true // 设置.notdef
};
subsetMap[0] = true;
// subset map
var cmap = ttf.cmap;
// unicode to index
Object.keys(cmap).forEach(function (c) {
if (subset.indexOf(+c) > -1) {
var _i = cmap[c];
subsetMap[_i] = true;
}
});
ttf.subsetMap = subsetMap;
var parsedGlyfMap = {};
// 循环解析subset相关的glyf包括复合字形相关的字形
var travelsParse = function travels(subsetMap) {
var newSubsetMap = {};
Object.keys(subsetMap).forEach(function (i) {
var index = +i;
parsedGlyfMap[index] = true;
// 当前的和下一个一样,或者最后一个无轮廓
if (loca[index] === loca[index + 1]) {
glyphs[index] = {
contours: []
};
} else {
glyphs[index] = (0, _parse.default)(reader, ttf, startOffset + loca[index]);
}
if (glyphs[index].compound) {
glyphs[index].glyfs.forEach(function (g) {
if (!parsedGlyfMap[g.glyphIndex]) {
newSubsetMap[g.glyphIndex] = true;
}
});
}
});
if (!(0, _lang.isEmptyObject)(newSubsetMap)) {
travels(newSubsetMap);
}
};
travelsParse(subsetMap);
return glyphs;
}
// 解析字体轮廓, 前n-1个
var i;
var l;
for (i = 0, l = numGlyphs - 1; i < l; i++) {
// 当前的和下一个一样,或者最后一个无轮廓
if (loca[i] === loca[i + 1]) {
glyphs[i] = {
contours: []
};
} else {
glyphs[i] = (0, _parse.default)(reader, ttf, startOffset + loca[i]);
}
}
// 最后一个轮廓
if (ttf.tables.glyf.length - loca[i] < 5) {
glyphs[i] = {
contours: []
};
} else {
glyphs[i] = (0, _parse.default)(reader, ttf, startOffset + loca[i]);
}
return glyphs;
},
write: _write.default,
size: _sizeof.default
});

View File

@ -0,0 +1,274 @@
"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;
}

View File

@ -0,0 +1,222 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = sizeof;
var _glyFlag = _interopRequireDefault(require("../../enum/glyFlag"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file 获取glyf的大小同时对glyf写入进行预处理
* @author mengke01(kekee000@gmail.com)
*/
/**
* 获取glyf的大小
*
* @param {Object} glyf glyf对象
* @param {Object} glyfSupport glyf相关统计
* @param {boolean} hinting 是否保留hints
* @param {boolean} writeZeroContoursGlyfData 是否写空轮廓 glyph
* @return {number} size大小
*/
function sizeofSimple(glyf, glyfSupport, hinting, writeZeroContoursGlyfData) {
if (!writeZeroContoursGlyfData && (!glyf.contours || !glyf.contours.length)) {
return 0;
}
// fixed header + endPtsOfContours
var result = 12 + (glyf.contours || []).length * 2 + (glyfSupport.flags || []).length;
(glyfSupport.xCoord || []).forEach(function (x) {
result += 0 <= x && x <= 0xFF ? 1 : 2;
});
(glyfSupport.yCoord || []).forEach(function (y) {
result += 0 <= y && y <= 0xFF ? 1 : 2;
});
return result + (hinting && glyf.instructions ? glyf.instructions.length : 0);
}
/**
* 复合图元size
*
* @param {Object} glyf glyf对象
* @param {boolean} hinting 是否保留hints, compound 图元暂时不做hinting
* @return {number} size大小
*/
// eslint-disable-next-line no-unused-vars
function sizeofCompound(glyf, hinting) {
var size = 10;
var transform;
glyf.glyfs.forEach(function (g) {
transform = g.transform;
// flags + glyfIndex
size += 4;
// a, b, c, d, e
// xy values or points
if (transform.e < 0 || transform.e > 0x7F || transform.f < 0 || transform.f > 0x7F) {
size += 4;
} else {
size += 2;
}
// 01 , 10
if (transform.b || transform.c) {
size += 8;
}
// scale
else if (transform.a !== 1 || transform.d !== 1) {
size += transform.a === transform.d ? 2 : 4;
}
});
return size;
}
/**
* 获取flags
*
* @param {Object} glyf glyf对象
* @param {Object} glyfSupport glyf相关统计
* @return {Array}
*/
function getFlags(glyf, glyfSupport) {
if (!glyf.contours || 0 === glyf.contours.length) {
return glyfSupport;
}
var flags = [];
var xCoord = [];
var yCoord = [];
var contours = glyf.contours;
var contour;
var prev;
var first = true;
for (var j = 0, cl = contours.length; j < cl; j++) {
contour = contours[j];
for (var i = 0, l = contour.length; i < l; i++) {
var point = contour[i];
if (first) {
xCoord.push(point.x);
yCoord.push(point.y);
first = false;
} else {
xCoord.push(point.x - prev.x);
yCoord.push(point.y - prev.y);
}
flags.push(point.onCurve ? _glyFlag.default.ONCURVE : 0);
prev = point;
}
}
// compress
var flagsC = [];
var xCoordC = [];
var yCoordC = [];
var x;
var y;
var prevFlag;
var repeatPoint = -1;
flags.forEach(function (flag, index) {
x = xCoord[index];
y = yCoord[index];
// 第一个
if (index === 0) {
if (-0xFF <= x && x <= 0xFF) {
flag += _glyFlag.default.XSHORT;
if (x >= 0) {
flag += _glyFlag.default.XSAME;
}
x = Math.abs(x);
}
if (-0xFF <= y && y <= 0xFF) {
flag += _glyFlag.default.YSHORT;
if (y >= 0) {
flag += _glyFlag.default.YSAME;
}
y = Math.abs(y);
}
flagsC.push(prevFlag = flag);
xCoordC.push(x);
yCoordC.push(y);
}
// 后续
else {
if (x === 0) {
flag += _glyFlag.default.XSAME;
} else {
if (-0xFF <= x && x <= 0xFF) {
flag += _glyFlag.default.XSHORT;
if (x > 0) {
flag += _glyFlag.default.XSAME;
}
x = Math.abs(x);
}
xCoordC.push(x);
}
if (y === 0) {
flag += _glyFlag.default.YSAME;
} else {
if (-0xFF <= y && y <= 0xFF) {
flag += _glyFlag.default.YSHORT;
if (y > 0) {
flag += _glyFlag.default.YSAME;
}
y = Math.abs(y);
}
yCoordC.push(y);
}
// repeat
if (flag === prevFlag) {
// 记录重复个数
if (-1 === repeatPoint) {
repeatPoint = flagsC.length - 1;
flagsC[repeatPoint] |= _glyFlag.default.REPEAT;
flagsC.push(1);
} else {
++flagsC[repeatPoint + 1];
}
} else {
repeatPoint = -1;
flagsC.push(prevFlag = flag);
}
}
});
glyfSupport.flags = flagsC;
glyfSupport.xCoord = xCoordC;
glyfSupport.yCoord = yCoordC;
return glyfSupport;
}
/**
* 对glyf数据进行预处理获取大小
*
* @param {Object} ttf ttf对象
* @return {number} 大小
*/
function sizeof(ttf) {
ttf.support.glyf = [];
var tableSize = 0;
var hinting = ttf.writeOptions ? ttf.writeOptions.hinting : false;
var writeZeroContoursGlyfData = ttf.writeOptions ? ttf.writeOptions.writeZeroContoursGlyfData : false;
ttf.glyf.forEach(function (glyf) {
var glyfSupport = {};
glyfSupport = glyf.compound ? glyfSupport : getFlags(glyf, glyfSupport);
var glyfSize = glyf.compound ? sizeofCompound(glyf, hinting) : sizeofSimple(glyf, glyfSupport, hinting, writeZeroContoursGlyfData);
var size = glyfSize;
// 4字节对齐
if (size % 4) {
size += 4 - size % 4;
}
glyfSupport.glyfSize = glyfSize;
glyfSupport.size = size;
ttf.support.glyf.push(glyfSupport);
tableSize += size;
});
ttf.support.glyf.tableSize = tableSize;
// 写header的indexToLocFormat
ttf.head.indexToLocFormat = tableSize > 65536 ? 1 : 0;
return ttf.support.glyf.tableSize;
}

View File

@ -0,0 +1,143 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = write;
var _componentFlag = _interopRequireDefault(require("../../enum/componentFlag"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file 写glyf数据
* @author mengke01(kekee000@gmail.com)
*/
/**
* 写glyf
*
* @param {Object} writer 写入器
* @param {Object} ttf ttf对象
* @return {Object} 写入器
*/
function write(writer, ttf) {
var hinting = ttf.writeOptions ? ttf.writeOptions.hinting : false;
var writeZeroContoursGlyfData = ttf.writeOptions ? ttf.writeOptions.writeZeroContoursGlyfData : false;
ttf.glyf.forEach(function (glyf, index) {
// 非复合图元没有轮廓则不写
if (!glyf.compound && !writeZeroContoursGlyfData && (!glyf.contours || !glyf.contours.length)) {
return;
}
// header
writer.writeInt16(glyf.compound ? -1 : (glyf.contours || []).length);
writer.writeInt16(glyf.xMin);
writer.writeInt16(glyf.yMin);
writer.writeInt16(glyf.xMax);
writer.writeInt16(glyf.yMax);
var i;
var l;
var flags;
// 复合图元
if (glyf.compound) {
for (i = 0, l = glyf.glyfs.length; i < l; i++) {
var g = glyf.glyfs[i];
flags = g.points ? 0 : _componentFlag.default.ARGS_ARE_XY_VALUES + _componentFlag.default.ROUND_XY_TO_GRID; // xy values
// more components
if (i < l - 1) {
flags += _componentFlag.default.MORE_COMPONENTS;
}
// use my metrics
flags += g.useMyMetrics ? _componentFlag.default.USE_MY_METRICS : 0;
// overlap compound
flags += g.overlapCompound ? _componentFlag.default.OVERLAP_COMPOUND : 0;
var transform = g.transform;
var a = transform.a;
var b = transform.b;
var c = transform.c;
var d = transform.d;
var e = g.points ? g.points[0] : transform.e;
var f = g.points ? g.points[1] : transform.f;
// xy values or points
// int 8 放不下则用int16放
if (e < 0 || e > 0x7F || f < 0 || f > 0x7F) {
flags += _componentFlag.default.ARG_1_AND_2_ARE_WORDS;
}
if (b || c) {
flags += _componentFlag.default.WE_HAVE_A_TWO_BY_TWO;
} else if ((a !== 1 || d !== 1) && a === d) {
flags += _componentFlag.default.WE_HAVE_A_SCALE;
} else if (a !== 1 || d !== 1) {
flags += _componentFlag.default.WE_HAVE_AN_X_AND_Y_SCALE;
}
writer.writeUint16(flags);
writer.writeUint16(g.glyphIndex);
if (_componentFlag.default.ARG_1_AND_2_ARE_WORDS & flags) {
writer.writeInt16(e);
writer.writeInt16(f);
} else {
writer.writeUint8(e);
writer.writeUint8(f);
}
if (_componentFlag.default.WE_HAVE_A_SCALE & flags) {
writer.writeInt16(Math.round(a * 16384));
} else if (_componentFlag.default.WE_HAVE_AN_X_AND_Y_SCALE & flags) {
writer.writeInt16(Math.round(a * 16384));
writer.writeInt16(Math.round(d * 16384));
} else if (_componentFlag.default.WE_HAVE_A_TWO_BY_TWO & flags) {
writer.writeInt16(Math.round(a * 16384));
writer.writeInt16(Math.round(b * 16384));
writer.writeInt16(Math.round(c * 16384));
writer.writeInt16(Math.round(d * 16384));
}
}
} else {
var endPtsOfContours = -1;
(glyf.contours || []).forEach(function (contour) {
endPtsOfContours += contour.length;
writer.writeUint16(endPtsOfContours);
});
// instruction
if (hinting && glyf.instructions) {
var instructions = glyf.instructions;
writer.writeUint16(instructions.length);
for (i = 0, l = instructions.length; i < l; i++) {
writer.writeUint8(instructions[i]);
}
} else {
writer.writeUint16(0);
}
// 获取暂存中的flags
flags = ttf.support.glyf[index].flags || [];
for (i = 0, l = flags.length; i < l; i++) {
writer.writeUint8(flags[i]);
}
var xCoord = ttf.support.glyf[index].xCoord || [];
for (i = 0, l = xCoord.length; i < l; i++) {
if (0 <= xCoord[i] && xCoord[i] <= 0xFF) {
writer.writeUint8(xCoord[i]);
} else {
writer.writeInt16(xCoord[i]);
}
}
var yCoord = ttf.support.glyf[index].yCoord || [];
for (i = 0, l = yCoord.length; i < l; i++) {
if (0 <= yCoord[i] && yCoord[i] <= 0xFF) {
writer.writeUint8(yCoord[i]);
} else {
writer.writeInt16(yCoord[i]);
}
}
}
// 4字节对齐
var glyfSize = ttf.support.glyf[index].glyfSize;
if (glyfSize % 4) {
writer.writeEmpty(4 - glyfSize % 4);
}
});
return writer;
}

View File

@ -0,0 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _table = _interopRequireDefault(require("./table"));
var _struct = _interopRequireDefault(require("./struct"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file head表
* @author mengke01(kekee000@gmail.com)
*/
var _default = exports.default = _table.default.create('head', [['version', _struct.default.Fixed], ['fontRevision', _struct.default.Fixed], ['checkSumAdjustment', _struct.default.Uint32], ['magickNumber', _struct.default.Uint32], ['flags', _struct.default.Uint16], ['unitsPerEm', _struct.default.Uint16], ['created', _struct.default.LongDateTime], ['modified', _struct.default.LongDateTime], ['xMin', _struct.default.Int16], ['yMin', _struct.default.Int16], ['xMax', _struct.default.Int16], ['yMax', _struct.default.Int16], ['macStyle', _struct.default.Uint16], ['lowestRecPPEM', _struct.default.Uint16], ['fontDirectionHint', _struct.default.Int16], ['indexToLocFormat', _struct.default.Int16], ['glyphDataFormat', _struct.default.Int16]]);

View File

@ -0,0 +1,16 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _table = _interopRequireDefault(require("./table"));
var _struct = _interopRequireDefault(require("./struct"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file hhea
* @author mengke01(kekee000@gmail.com)
*
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6hhea.html
*/
var _default = exports.default = _table.default.create('hhea', [['version', _struct.default.Fixed], ['ascent', _struct.default.Int16], ['descent', _struct.default.Int16], ['lineGap', _struct.default.Int16], ['advanceWidthMax', _struct.default.Uint16], ['minLeftSideBearing', _struct.default.Int16], ['minRightSideBearing', _struct.default.Int16], ['xMaxExtent', _struct.default.Int16], ['caretSlopeRise', _struct.default.Int16], ['caretSlopeRun', _struct.default.Int16], ['caretOffset', _struct.default.Int16], ['reserved0', _struct.default.Int16], ['reserved1', _struct.default.Int16], ['reserved2', _struct.default.Int16], ['reserved3', _struct.default.Int16], ['metricDataFormat', _struct.default.Int16], ['numOfLongHorMetrics', _struct.default.Uint16]]);

View File

@ -0,0 +1,73 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _table = _interopRequireDefault(require("./table"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file hmtx
* @author mengke01(kekee000@gmail.com)
*
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6hmtx.html
*/
var _default = exports.default = _table.default.create('hmtx', [], {
read: function read(reader, ttf) {
var offset = this.offset;
reader.seek(offset);
var numOfLongHorMetrics = ttf.hhea.numOfLongHorMetrics;
var hMetrics = [];
var i;
var hMetric;
for (i = 0; i < numOfLongHorMetrics; ++i) {
hMetric = {};
hMetric.advanceWidth = reader.readUint16();
hMetric.leftSideBearing = reader.readInt16();
hMetrics.push(hMetric);
}
// 最后一个宽度
var advanceWidth = hMetrics[numOfLongHorMetrics - 1].advanceWidth;
var numOfLast = ttf.maxp.numGlyphs - numOfLongHorMetrics;
// 获取后续的hmetrics
for (i = 0; i < numOfLast; ++i) {
hMetric = {};
hMetric.advanceWidth = advanceWidth;
hMetric.leftSideBearing = reader.readInt16();
hMetrics.push(hMetric);
}
return hMetrics;
},
write: function write(writer, ttf) {
var i;
var numOfLongHorMetrics = ttf.hhea.numOfLongHorMetrics;
for (i = 0; i < numOfLongHorMetrics; ++i) {
writer.writeUint16(ttf.glyf[i].advanceWidth);
writer.writeInt16(ttf.glyf[i].leftSideBearing);
}
// 最后一个宽度
var numOfLast = ttf.glyf.length - numOfLongHorMetrics;
for (i = 0; i < numOfLast; ++i) {
writer.writeInt16(ttf.glyf[numOfLongHorMetrics + i].leftSideBearing);
}
return writer;
},
size: function size(ttf) {
// 计算同最后一个advanceWidth相等的元素个数
var numOfLast = 0;
// 最后一个advanceWidth
var advanceWidth = ttf.glyf[ttf.glyf.length - 1].advanceWidth;
for (var i = ttf.glyf.length - 2; i >= 0; i--) {
if (advanceWidth === ttf.glyf[i].advanceWidth) {
numOfLast++;
} else {
break;
}
}
ttf.hhea.numOfLongHorMetrics = ttf.glyf.length - numOfLast;
return 4 * ttf.hhea.numOfLongHorMetrics + 2 * numOfLast;
}
});

View File

@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _table = _interopRequireDefault(require("./table"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file kern
* @author fr33z00(https://github.com/fr33z00)
*
* @reference: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kern.html
*/
var _default = exports.default = _table.default.create('kern', [], {
read: function read(reader, ttf) {
var length = ttf.tables.kern.length;
return reader.readBytes(this.offset, length);
},
write: function write(writer, ttf) {
if (ttf.kern) {
writer.writeBytes(ttf.kern, ttf.kern.length);
}
},
size: function size(ttf) {
return ttf.kern ? ttf.kern.length : 0;
}
});

View File

@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _table = _interopRequireDefault(require("./table"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file kerx
* @author mengke01(kekee000@gmail.com)
*
* @reference: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kerx.html
*/
var _default = exports.default = _table.default.create('kerx', [], {
read: function read(reader, ttf) {
var length = ttf.tables.kerx.length;
return reader.readBytes(this.offset, length);
},
write: function write(writer, ttf) {
if (ttf.kerx) {
writer.writeBytes(ttf.kerx, ttf.kerx.length);
}
},
size: function size(ttf) {
return ttf.kerx ? ttf.kerx.length : 0;
}
});

View File

@ -0,0 +1,58 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _table = _interopRequireDefault(require("./table"));
var _struct = _interopRequireDefault(require("./struct"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file loca表
* @author mengke01(kekee000@gmail.com)
*/
var _default = exports.default = _table.default.create('loca', [], {
read: function read(reader, ttf) {
var offset = this.offset;
var indexToLocFormat = ttf.head.indexToLocFormat;
// indexToLocFormat有2字节和4字节的区别
var type = _struct.default.names[indexToLocFormat === 0 ? _struct.default.Uint16 : _struct.default.Uint32];
var size = indexToLocFormat === 0 ? 2 : 4; // 字节大小
var sizeRatio = indexToLocFormat === 0 ? 2 : 1; // 真实地址偏移
var wordOffset = [];
reader.seek(offset);
var numGlyphs = ttf.maxp.numGlyphs;
for (var i = 0; i < numGlyphs; ++i) {
wordOffset.push(reader.read(type, offset, false) * sizeRatio);
offset += size;
}
return wordOffset;
},
write: function write(writer, ttf) {
var glyfSupport = ttf.support.glyf;
var offset = ttf.support.glyf.offset || 0;
var indexToLocFormat = ttf.head.indexToLocFormat;
var sizeRatio = indexToLocFormat === 0 ? 0.5 : 1;
var numGlyphs = ttf.glyf.length;
for (var i = 0; i < numGlyphs; ++i) {
if (indexToLocFormat) {
writer.writeUint32(offset);
} else {
writer.writeUint16(offset);
}
offset += glyfSupport[i].size * sizeRatio;
}
// write extra
if (indexToLocFormat) {
writer.writeUint32(offset);
} else {
writer.writeUint16(offset);
}
return writer;
},
size: function size(ttf) {
var locaCount = ttf.glyf.length + 1;
return ttf.head.indexToLocFormat ? locaCount * 4 : locaCount * 2;
}
});

View File

@ -0,0 +1,22 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _table = _interopRequireDefault(require("./table"));
var _struct = _interopRequireDefault(require("./struct"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file maxp
* @author mengke01(kekee000@gmail.com)
*/
var _default = exports.default = _table.default.create('maxp', [['version', _struct.default.Fixed], ['numGlyphs', _struct.default.Uint16], ['maxPoints', _struct.default.Uint16], ['maxContours', _struct.default.Uint16], ['maxCompositePoints', _struct.default.Uint16], ['maxCompositeContours', _struct.default.Uint16], ['maxZones', _struct.default.Uint16], ['maxTwilightPoints', _struct.default.Uint16], ['maxStorage', _struct.default.Uint16], ['maxFunctionDefs', _struct.default.Uint16], ['maxInstructionDefs', _struct.default.Uint16], ['maxStackElements', _struct.default.Uint16], ['maxSizeOfInstructions', _struct.default.Uint16], ['maxComponentElements', _struct.default.Uint16], ['maxComponentDepth', _struct.default.Int16]], {
write: function write(writer, ttf) {
_table.default.write.call(this, writer, ttf.support);
return writer;
},
size: function size() {
return 32;
}
});

View File

@ -0,0 +1,146 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _table = _interopRequireDefault(require("./table"));
var _nameId = _interopRequireDefault(require("../enum/nameId"));
var _string = _interopRequireDefault(require("../util/string"));
var _platform = _interopRequireDefault(require("../enum/platform"));
var _encoding = require("../enum/encoding");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file name表
* @author mengke01(kekee000@gmail.com)
*/
var _default = exports.default = _table.default.create('name', [], {
read: function read(reader) {
var offset = this.offset;
reader.seek(offset);
var nameTbl = {};
nameTbl.format = reader.readUint16();
nameTbl.count = reader.readUint16();
nameTbl.stringOffset = reader.readUint16();
var nameRecordTbl = [];
var count = nameTbl.count;
var i;
var nameRecord;
for (i = 0; i < count; ++i) {
nameRecord = {};
nameRecord.platform = reader.readUint16();
nameRecord.encoding = reader.readUint16();
nameRecord.language = reader.readUint16();
nameRecord.nameId = reader.readUint16();
nameRecord.length = reader.readUint16();
nameRecord.offset = reader.readUint16();
nameRecordTbl.push(nameRecord);
}
offset += nameTbl.stringOffset;
// 读取字符名字
for (i = 0; i < count; ++i) {
nameRecord = nameRecordTbl[i];
nameRecord.name = reader.readBytes(offset + nameRecord.offset, nameRecord.length);
}
var names = {};
// mac 下的english name
var platform = _platform.default.Macintosh;
var encoding = _encoding.mac.Default;
var language = 0;
// 如果有windows 下的 english则用windows下的 name
if (nameRecordTbl.some(function (record) {
return record.platform === _platform.default.Microsoft && record.encoding === _encoding.win.UCS2 && record.language === 1033;
})) {
platform = _platform.default.Microsoft;
encoding = _encoding.win.UCS2;
language = 1033;
}
for (i = 0; i < count; ++i) {
nameRecord = nameRecordTbl[i];
if (nameRecord.platform === platform && nameRecord.encoding === encoding && nameRecord.language === language && _nameId.default[nameRecord.nameId]) {
names[_nameId.default[nameRecord.nameId]] = language === 0 ? _string.default.getUTF8String(nameRecord.name) : _string.default.getUCS2String(nameRecord.name);
}
}
return names;
},
write: function write(writer, ttf) {
var nameRecordTbl = ttf.support.name;
writer.writeUint16(0); // format
writer.writeUint16(nameRecordTbl.length); // count
writer.writeUint16(6 + nameRecordTbl.length * 12); // string offset
// write name tbl header
var offset = 0;
nameRecordTbl.forEach(function (nameRecord) {
writer.writeUint16(nameRecord.platform);
writer.writeUint16(nameRecord.encoding);
writer.writeUint16(nameRecord.language);
writer.writeUint16(nameRecord.nameId);
writer.writeUint16(nameRecord.name.length);
writer.writeUint16(offset); // offset
offset += nameRecord.name.length;
});
// write name tbl strings
nameRecordTbl.forEach(function (nameRecord) {
writer.writeBytes(nameRecord.name);
});
return writer;
},
size: function size(ttf) {
var names = ttf.name;
var nameRecordTbl = [];
// 写入name信息
// 这里为了简化书写,仅支持英文编码字符,
// 中文编码字符将被转化成url encode
var size = 6;
Object.keys(names).forEach(function (name) {
var id = _nameId.default.names[name];
var utf8Bytes = _string.default.toUTF8Bytes(names[name]);
var usc2Bytes = _string.default.toUCS2Bytes(names[name]);
if (undefined !== id) {
// mac
nameRecordTbl.push({
nameId: id,
platform: 1,
encoding: 0,
language: 0,
name: utf8Bytes
});
// windows
nameRecordTbl.push({
nameId: id,
platform: 3,
encoding: 1,
language: 1033,
name: usc2Bytes
});
// 子表大小
size += 12 * 2 + utf8Bytes.length + usc2Bytes.length;
}
});
var namingOrder = ['platform', 'encoding', 'language', 'nameId'];
nameRecordTbl = nameRecordTbl.sort(function (a, b) {
var l = 0;
namingOrder.some(function (name) {
var o = a[name] - b[name];
if (o) {
l = o;
return true;
}
return false;
});
return l;
});
// 保存预处理信息
ttf.support.name = nameRecordTbl;
return size;
}
});

View File

@ -0,0 +1,127 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _table = _interopRequireDefault(require("./table"));
var _struct = _interopRequireDefault(require("./struct"));
var _string = _interopRequireDefault(require("../util/string"));
var _unicodeName = _interopRequireDefault(require("../enum/unicodeName"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file post
* @author mengke01(kekee000@gmail.com)
*
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6post.html
*/
var Posthead = _table.default.create('posthead', [['format', _struct.default.Fixed], ['italicAngle', _struct.default.Fixed], ['underlinePosition', _struct.default.Int16], ['underlineThickness', _struct.default.Int16], ['isFixedPitch', _struct.default.Uint32], ['minMemType42', _struct.default.Uint32], ['maxMemType42', _struct.default.Uint32], ['minMemType1', _struct.default.Uint32], ['maxMemType1', _struct.default.Uint32]]);
var _default = exports.default = _table.default.create('post', [], {
read: function read(reader, ttf) {
var format = reader.readFixed(this.offset);
// 读取表头
var tbl = new Posthead(this.offset).read(reader, ttf);
// format2
if (format === 2) {
var numberOfGlyphs = reader.readUint16();
var glyphNameIndex = [];
for (var i = 0; i < numberOfGlyphs; ++i) {
glyphNameIndex.push(reader.readUint16());
}
var pascalStringOffset = reader.offset;
var pascalStringLength = ttf.tables.post.length - (pascalStringOffset - this.offset);
var pascalStringBytes = reader.readBytes(reader.offset, pascalStringLength);
tbl.nameIndex = glyphNameIndex; // 设置glyf名字索引
tbl.names = _string.default.getPascalString(pascalStringBytes); // glyf名字数组
}
// deprecated
else if (format === 2.5) {
tbl.format = 3;
}
return tbl;
},
write: function write(writer, ttf) {
var post = ttf.post || {
format: 3
};
// write header
writer.writeFixed(post.format); // format
writer.writeFixed(post.italicAngle || 0); // italicAngle
writer.writeInt16(post.underlinePosition || 0); // underlinePosition
writer.writeInt16(post.underlineThickness || 0); // underlineThickness
writer.writeUint32(post.isFixedPitch || 0); // isFixedPitch
writer.writeUint32(post.minMemType42 || 0); // minMemType42
writer.writeUint32(post.maxMemType42 || 0); // maxMemType42
writer.writeUint32(post.minMemType1 || 0); // minMemType1
writer.writeUint32(post.maxMemType1 || 0); // maxMemType1
// version 3 不设置post信息
if (post.format === 2) {
var numberOfGlyphs = ttf.glyf.length;
writer.writeUint16(numberOfGlyphs); // numberOfGlyphs
// write glyphNameIndex
var nameIndex = ttf.support.post.nameIndex;
for (var i = 0, l = nameIndex.length; i < l; i++) {
writer.writeUint16(nameIndex[i]);
}
// write names
ttf.support.post.names.forEach(function (name) {
writer.writeBytes(name);
});
}
},
size: function size(ttf) {
var numberOfGlyphs = ttf.glyf.length;
ttf.post = ttf.post || {};
ttf.post.format = ttf.post.format || 3;
ttf.post.maxMemType1 = numberOfGlyphs;
// version 3 不设置post信息
if (ttf.post.format === 3 || ttf.post.format === 1) {
return 32;
}
// version 2
var size = 34 + numberOfGlyphs * 2; // header + numberOfGlyphs + numberOfGlyphs * 2
var glyphNames = [];
var nameIndexArr = [];
var nameIndex = 0;
// 获取 name的大小
for (var i = 0; i < numberOfGlyphs; i++) {
// .notdef
if (i === 0) {
nameIndexArr.push(0);
} else {
var glyf = ttf.glyf[i];
var unicode = glyf.unicode ? glyf.unicode[0] : 0;
var unicodeNameIndex = _unicodeName.default[unicode];
if (undefined !== unicodeNameIndex) {
nameIndexArr.push(unicodeNameIndex);
} else {
// 这里需要注意,"" 有可能是"\3" length不为0但是是空字符串
var name = glyf.name;
if (!name || name.charCodeAt(0) < 32) {
nameIndexArr.push(258 + nameIndex++);
glyphNames.push([0]);
size++;
} else {
nameIndexArr.push(258 + nameIndex++);
var bytes = _string.default.toPascalStringBytes(name); // pascal string bytes
glyphNames.push(bytes);
size += bytes.length;
}
}
}
}
ttf.support.post = {
nameIndex: nameIndexArr,
names: glyphNames
};
return size;
}
});

View File

@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _table = _interopRequireDefault(require("./table"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file prep表
* @author mengke01(kekee000@gmail.com)
*
* @reference: http://www.microsoft.com/typography/otspec140/prep.htm
*/
var _default = exports.default = _table.default.create('prep', [], {
read: function read(reader, ttf) {
var length = ttf.tables.prep.length;
return reader.readBytes(this.offset, length);
},
write: function write(writer, ttf) {
if (ttf.prep) {
writer.writeBytes(ttf.prep, ttf.prep.length);
}
},
size: function size(ttf) {
return ttf.prep ? ttf.prep.length : 0;
}
});

View File

@ -0,0 +1,43 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
/**
* @file ttf基本数据结构
* @author mengke01(kekee000@gmail.com)
*
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6.html
*/
var struct = {
Int8: 1,
Uint8: 2,
Int16: 3,
Uint16: 4,
Int32: 5,
Uint32: 6,
Fixed: 7,
// 32-bit signed fixed-point number (16.16)
FUnit: 8,
// Smallest measurable distance in the em space
// 16-bit signed fixed number with the low 14 bits of fraction
F2Dot14: 11,
// The long internal format of a date in seconds since 12:00 midnight,
// January 1, 1904. It is represented as a signed 64-bit integer.
LongDateTime: 12,
// extend data type
Char: 13,
String: 14,
Bytes: 15,
Uint24: 20
};
// 反转名字查找
var names = {};
Object.keys(struct).forEach(function (key) {
names[struct[key]] = key;
});
struct.names = names;
var _default = exports.default = struct;

View File

@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _head = _interopRequireDefault(require("./head"));
var _maxp = _interopRequireDefault(require("./maxp"));
var _cmap = _interopRequireDefault(require("./cmap"));
var _name = _interopRequireDefault(require("./name"));
var _hhea = _interopRequireDefault(require("./hhea"));
var _hmtx = _interopRequireDefault(require("./hmtx"));
var _post = _interopRequireDefault(require("./post"));
var _OS = _interopRequireDefault(require("./OS2"));
var _CFF = _interopRequireDefault(require("./CFF"));
var _GPOS = _interopRequireDefault(require("./GPOS"));
var _kern = _interopRequireDefault(require("./kern"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file otf字体格式支持的表
* @author mengke01(kekee000@gmail.com)
*/
var _default = exports.default = {
head: _head.default,
maxp: _maxp.default,
cmap: _cmap.default,
name: _name.default,
hhea: _hhea.default,
hmtx: _hmtx.default,
post: _post.default,
'OS/2': _OS.default,
CFF: _CFF.default,
GPOS: _GPOS.default,
kern: _kern.default
};

View File

@ -0,0 +1,47 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _head = _interopRequireDefault(require("./head"));
var _maxp = _interopRequireDefault(require("./maxp"));
var _loca = _interopRequireDefault(require("./loca"));
var _cmap = _interopRequireDefault(require("./cmap"));
var _glyf = _interopRequireDefault(require("./glyf"));
var _name = _interopRequireDefault(require("./name"));
var _hhea = _interopRequireDefault(require("./hhea"));
var _hmtx = _interopRequireDefault(require("./hmtx"));
var _post = _interopRequireDefault(require("./post"));
var _OS = _interopRequireDefault(require("./OS2"));
var _fpgm = _interopRequireDefault(require("./fpgm"));
var _cvt = _interopRequireDefault(require("./cvt"));
var _prep = _interopRequireDefault(require("./prep"));
var _gasp = _interopRequireDefault(require("./gasp"));
var _GPOS = _interopRequireDefault(require("./GPOS"));
var _kern = _interopRequireDefault(require("./kern"));
var _kerx = _interopRequireDefault(require("./kerx"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file ttf读取和写入支持的表
* @author mengke01(kekee000@gmail.com)
*/
var _default = exports.default = {
head: _head.default,
maxp: _maxp.default,
loca: _loca.default,
cmap: _cmap.default,
glyf: _glyf.default,
name: _name.default,
hhea: _hhea.default,
hmtx: _hmtx.default,
post: _post.default,
'OS/2': _OS.default,
fpgm: _fpgm.default,
cvt: _cvt.default,
prep: _prep.default,
gasp: _gasp.default,
GPOS: _GPOS.default,
kern: _kern.default,
kerx: _kerx.default
};

View File

@ -0,0 +1,200 @@
"use strict";
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); }
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _struct = _interopRequireDefault(require("./struct"));
var _error = _interopRequireDefault(require("../error"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
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); }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /**
* @file ttf表基类
* @author mengke01(kekee000@gmail.com)
*/
/* eslint-disable no-invalid-this */
/**
* 读取表结构
*
* @param {Reader} reader reader对象
* @return {Object} 当前对象
*/
function read(reader) {
var offset = this.offset;
if (undefined !== offset) {
reader.seek(offset);
}
var me = this;
this.struct.forEach(function (item) {
var name = item[0];
var type = item[1];
var typeName = null;
switch (type) {
case _struct.default.Int8:
case _struct.default.Uint8:
case _struct.default.Int16:
case _struct.default.Uint16:
case _struct.default.Int32:
case _struct.default.Uint32:
typeName = _struct.default.names[type];
me[name] = reader.read(typeName);
break;
case _struct.default.Fixed:
me[name] = reader.readFixed();
break;
case _struct.default.LongDateTime:
me[name] = reader.readLongDateTime();
break;
case _struct.default.Bytes:
me[name] = reader.readBytes(reader.offset, item[2] || 0);
break;
case _struct.default.Char:
me[name] = reader.readChar();
break;
case _struct.default.String:
me[name] = reader.readString(reader.offset, item[2] || 0);
break;
default:
_error.default.raise(10003, name, type);
}
});
return this.valueOf();
}
/**
* 写表结构
*
* @param {Object} writer writer对象
* @param {Object} ttf 已解析的ttf对象
*
* @return {Writer} 返回writer对象
*/
function write(writer, ttf) {
var table = ttf[this.name];
if (!table) {
_error.default.raise(10203, this.name);
}
this.struct.forEach(function (item) {
var name = item[0];
var type = item[1];
var typeName = null;
switch (type) {
case _struct.default.Int8:
case _struct.default.Uint8:
case _struct.default.Int16:
case _struct.default.Uint16:
case _struct.default.Int32:
case _struct.default.Uint32:
typeName = _struct.default.names[type];
writer.write(typeName, table[name]);
break;
case _struct.default.Fixed:
writer.writeFixed(table[name]);
break;
case _struct.default.LongDateTime:
writer.writeLongDateTime(table[name]);
break;
case _struct.default.Bytes:
writer.writeBytes(table[name], item[2] || 0);
break;
case _struct.default.Char:
writer.writeChar(table[name]);
break;
case _struct.default.String:
writer.writeString(table[name], item[2] || 0);
break;
default:
_error.default.raise(10003, name, type);
}
});
return writer;
}
/**
* 获取ttf表的size大小
*
* @param {string} name 表名
* @return {number} 表大小
*/
function size() {
var sz = 0;
this.struct.forEach(function (item) {
var type = item[1];
switch (type) {
case _struct.default.Int8:
case _struct.default.Uint8:
sz += 1;
break;
case _struct.default.Int16:
case _struct.default.Uint16:
sz += 2;
break;
case _struct.default.Int32:
case _struct.default.Uint32:
case _struct.default.Fixed:
sz += 4;
break;
case _struct.default.LongDateTime:
sz += 8;
break;
case _struct.default.Bytes:
sz += item[2] || 0;
break;
case _struct.default.Char:
sz += 1;
break;
case _struct.default.String:
sz += item[2] || 0;
break;
default:
_error.default.raise(10003, name, type);
}
});
return sz;
}
/**
* 获取对象的值
*
* @return {*} 当前对象的值
*/
function valueOf() {
var val = {};
var me = this;
this.struct.forEach(function (item) {
val[item[0]] = me[item[0]];
});
return val;
}
var _default = exports.default = {
read: read,
write: write,
size: size,
valueOf: valueOf,
/**
* 创建一个表结构
*
* @param {string} name 表名
* @param {Array<[string, number]>} struct 表结构
* @param {Object} proto 原型
* @return {Function} 表构造函数
*/
create: function create(name, struct, proto) {
var Table = /*#__PURE__*/_createClass(function Table(offset) {
_classCallCheck(this, Table);
this.name = name;
this.struct = struct;
this.offset = offset;
});
Table.prototype.read = read;
Table.prototype.write = write;
Table.prototype.size = size;
Table.prototype.valueOf = valueOf;
Object.assign(Table.prototype, proto);
return Table;
}
};

860
vendor/fonteditor-core/lib/ttf/ttf.js vendored Normal file
View File

@ -0,0 +1,860 @@
"use strict";
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); }
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _lang = require("../common/lang");
var _string = _interopRequireDefault(require("./util/string"));
var _pathAdjust = _interopRequireDefault(require("../graphics/pathAdjust"));
var _pathCeil = _interopRequireDefault(require("../graphics/pathCeil"));
var _computeBoundingBox = require("../graphics/computeBoundingBox");
var _compound2simpleglyf = _interopRequireDefault(require("./util/compound2simpleglyf"));
var _glyfAdjust = _interopRequireDefault(require("./util/glyfAdjust"));
var _optimizettf = _interopRequireDefault(require("./util/optimizettf"));
var _default = _interopRequireDefault(require("./data/default"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
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); }
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } /**
* @file ttf相关处理对象
* @author mengke01(kekee000@gmail.com)
*/
/**
* 缩放到EM框
*
* @param {Array} glyfList glyf列表
* @param {number} ascent 上升
* @param {number} descent 下降
* @param {number} adjustToEmPadding 顶部和底部留白
* @return {Array} glyfList
*/
function adjustToEmBox(glyfList, ascent, descent, adjustToEmPadding) {
glyfList.forEach(function (g) {
if (g.contours && g.contours.length) {
var rightSideBearing = g.advanceWidth - g.xMax;
var bound = _computeBoundingBox.computePath.apply(void 0, _toConsumableArray(g.contours));
var scale = (ascent - descent - adjustToEmPadding) / bound.height;
var center = (ascent + descent) / 2;
var yOffset = center - (bound.y + bound.height / 2) * scale;
g.contours.forEach(function (contour) {
if (scale !== 1) {
(0, _pathAdjust.default)(contour, scale, scale);
}
(0, _pathAdjust.default)(contour, 1, 1, 0, yOffset);
(0, _pathCeil.default)(contour);
});
var box = _computeBoundingBox.computePathBox.apply(void 0, _toConsumableArray(g.contours));
g.xMin = box.x;
g.xMax = box.x + box.width;
g.yMin = box.y;
g.yMax = box.y + box.height;
g.leftSideBearing = g.xMin;
g.advanceWidth = g.xMax + rightSideBearing;
}
});
return glyfList;
}
/**
* 调整字形位置
*
* @param {Array} glyfList 字形列表
* @param {number=} leftSideBearing 左边距
* @param {number=} rightSideBearing 右边距
* @param {number=} verticalAlign 垂直对齐
*
* @return {Array} 改变的列表
*/
function adjustPos(glyfList, leftSideBearing, rightSideBearing, verticalAlign) {
var changed = false;
// 左边轴
if (null != leftSideBearing) {
changed = true;
glyfList.forEach(function (g) {
if (g.leftSideBearing !== leftSideBearing) {
(0, _glyfAdjust.default)(g, 1, 1, leftSideBearing - g.leftSideBearing);
}
});
}
// 右边轴
if (null != rightSideBearing) {
changed = true;
glyfList.forEach(function (g) {
g.advanceWidth = g.xMax + rightSideBearing;
});
}
// 基线高度
if (null != verticalAlign) {
changed = true;
glyfList.forEach(function (g) {
if (g.contours && g.contours.length) {
var bound = _computeBoundingBox.computePath.apply(void 0, _toConsumableArray(g.contours));
var offset = verticalAlign - bound.y;
(0, _glyfAdjust.default)(g, 1, 1, 0, offset);
}
});
}
return changed ? glyfList : [];
}
/**
* 合并两个ttfObject此处仅合并简单字形
*
* @param {Object} ttf ttfObject
* @param {Object} imported ttfObject
* @param {Object} options 参数选项
* @param {boolean} options.scale 是否自动缩放默认true
* @param {boolean} options.adjustGlyf 是否调整字形以适应边界
* ( options.scale 互斥)
*
* @return {Object} 合并后的ttfObject
*/
function merge(ttf, imported) {
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {
scale: true
};
var list = imported.glyf.filter(function (g) {
return (
// 简单轮廓
g.contours && g.contours.length
// 非预定义字形
&& g.name !== '.notdef' && g.name !== '.null' && g.name !== 'nonmarkingreturn'
);
});
// 调整字形以适应边界
if (options.adjustGlyf) {
var ascent = ttf.hhea.ascent;
var descent = ttf.hhea.descent;
var adjustToEmPadding = 16;
adjustPos(list, 16, 16);
adjustToEmBox(list, ascent, descent, adjustToEmPadding);
list.forEach(function (g) {
ttf.glyf.push(g);
});
}
// 根据unitsPerEm 进行缩放
else if (options.scale) {
var scale = 1;
// 调整glyf对导入的轮廓进行缩放处理
if (imported.head.unitsPerEm && imported.head.unitsPerEm !== ttf.head.unitsPerEm) {
scale = ttf.head.unitsPerEm / imported.head.unitsPerEm;
}
list.forEach(function (g) {
(0, _glyfAdjust.default)(g, scale, scale);
ttf.glyf.push(g);
});
}
return list;
}
var TTF = exports.default = /*#__PURE__*/function () {
/**
* ttf读取函数
*
* @constructor
* @param {Object} ttf ttf文件结构
*/
function TTF(ttf) {
_classCallCheck(this, TTF);
this.ttf = ttf;
}
/**
* 获取所有的字符信息
*
* @return {Object} 字符信息
*/
return _createClass(TTF, [{
key: "codes",
value: function codes() {
return Object.keys(this.ttf.cmap);
}
/**
* 根据编码获取字形索引
*
* @param {string} c 字符或者字符编码
*
* @return {?number} 返回glyf索引号
*/
}, {
key: "getGlyfIndexByCode",
value: function getGlyfIndexByCode(c) {
var charCode = typeof c === 'number' ? c : c.codePointAt(0);
var glyfIndex = this.ttf.cmap[charCode] || -1;
return glyfIndex;
}
/**
* 根据索引获取字形
*
* @param {number} glyfIndex glyf的索引
*
* @return {?Object} 返回glyf对象
*/
}, {
key: "getGlyfByIndex",
value: function getGlyfByIndex(glyfIndex) {
var glyfList = this.ttf.glyf;
var glyf = glyfList[glyfIndex];
return glyf;
}
/**
* 根据编码获取字形
*
* @param {string} c 字符或者字符编码
*
* @return {?Object} 返回glyf对象
*/
}, {
key: "getGlyfByCode",
value: function getGlyfByCode(c) {
var glyfIndex = this.getGlyfIndexByCode(c);
return this.getGlyfByIndex(glyfIndex);
}
/**
* 设置ttf对象
*
* @param {Object} ttf ttf对象
* @return {this}
*/
}, {
key: "set",
value: function set(ttf) {
this.ttf = ttf;
return this;
}
/**
* 获取ttf对象
*
* @return {ttfObject} ttf ttf对象
*/
}, {
key: "get",
value: function get() {
return this.ttf;
}
/**
* 添加glyf
*
* @param {Object} glyf glyf对象
*
* @return {number} 添加的glyf
*/
}, {
key: "addGlyf",
value: function addGlyf(glyf) {
return this.insertGlyf(glyf);
}
/**
* 插入glyf
*
* @param {Object} glyf glyf对象
* @param {Object} insertIndex 插入的索引
* @return {number} 添加的glyf
*/
}, {
key: "insertGlyf",
value: function insertGlyf(glyf, insertIndex) {
if (insertIndex >= 0 && insertIndex < this.ttf.glyf.length) {
this.ttf.glyf.splice(insertIndex, 0, glyf);
} else {
this.ttf.glyf.push(glyf);
}
return [glyf];
}
/**
* 合并两个ttfObject此处仅合并简单字形
*
* @param {Object} imported ttfObject
* @param {Object} options 参数选项
* @param {boolean} options.scale 是否自动缩放
* @param {boolean} options.adjustGlyf 是否调整字形以适应边界
* ( options.scale 参数互斥)
*
* @return {Array} 添加的glyf
*/
}, {
key: "mergeGlyf",
value: function mergeGlyf(imported, options) {
var list = merge(this.ttf, imported, options);
return list;
}
/**
* 删除指定字形
*
* @param {Array} indexList 索引列表
* @return {Array} 删除的glyf
*/
}, {
key: "removeGlyf",
value: function removeGlyf(indexList) {
var glyf = this.ttf.glyf;
var removed = [];
for (var i = glyf.length - 1; i >= 0; i--) {
if (indexList.indexOf(i) >= 0) {
removed.push(glyf[i]);
glyf.splice(i, 1);
}
}
return removed;
}
/**
* 设置unicode代码
*
* @param {string} unicode unicode代码 $E021, $22
* @param {Array=} indexList 索引列表
* @param {boolean} isGenerateName 是否生成name
* @return {Array} 改变的glyf
*/
}, {
key: "setUnicode",
value: function setUnicode(unicode, indexList, isGenerateName) {
var glyf = this.ttf.glyf;
var list = [];
if (indexList && indexList.length) {
var first = indexList.indexOf(0);
if (first >= 0) {
indexList.splice(first, 1);
}
list = indexList.map(function (item) {
return glyf[item];
});
} else {
list = glyf.slice(1);
}
// 需要选出 unicode >32 的glyf
if (list.length > 1) {
var less32 = function less32(u) {
return u < 33;
};
list = list.filter(function (g) {
return !g.unicode || !g.unicode.some(less32);
});
}
if (list.length) {
unicode = Number('0x' + unicode.slice(1));
list.forEach(function (g) {
// 空格有可能会放入 nonmarkingreturn 因此不做编码
if (unicode === 0xA0 || unicode === 0x3000) {
unicode++;
}
g.unicode = [unicode];
if (isGenerateName) {
g.name = _string.default.getUnicodeName(unicode);
}
unicode++;
});
}
return list;
}
/**
* 生成字形名称
*
* @param {Array=} indexList 索引列表
* @return {Array} 改变的glyf
*/
}, {
key: "genGlyfName",
value: function genGlyfName(indexList) {
var glyf = this.ttf.glyf;
var list = [];
if (indexList && indexList.length) {
list = indexList.map(function (item) {
return glyf[item];
});
} else {
list = glyf;
}
if (list.length) {
var first = this.ttf.glyf[0];
list.forEach(function (g) {
if (g === first) {
g.name = '.notdef';
} else if (g.unicode && g.unicode.length) {
g.name = _string.default.getUnicodeName(g.unicode[0]);
} else {
g.name = '.notdef';
}
});
}
return list;
}
/**
* 清除字形名称
*
* @param {Array=} indexList 索引列表
* @return {Array} 改变的glyf
*/
}, {
key: "clearGlyfName",
value: function clearGlyfName(indexList) {
var glyf = this.ttf.glyf;
var list = [];
if (indexList && indexList.length) {
list = indexList.map(function (item) {
return glyf[item];
});
} else {
list = glyf;
}
if (list.length) {
list.forEach(function (g) {
delete g.name;
});
}
return list;
}
/**
* 添加并体替换指定的glyf
*
* @param {Array} glyfList 添加的列表
* @param {Array=} indexList 需要替换的索引列表
* @return {Array} 改变的glyf
*/
}, {
key: "appendGlyf",
value: function appendGlyf(glyfList, indexList) {
var glyf = this.ttf.glyf;
var result = glyfList.slice(0);
if (indexList && indexList.length) {
var l = Math.min(glyfList.length, indexList.length);
for (var i = 0; i < l; i++) {
glyf[indexList[i]] = glyfList[i];
}
glyfList = glyfList.slice(l);
}
if (glyfList.length) {
Array.prototype.splice.apply(glyf, [glyf.length, 0].concat(_toConsumableArray(glyfList)));
}
return result;
}
/**
* 调整glyf位置
*
* @param {Array=} indexList 索引列表
* @param {Object} setting 选项
* @param {number=} setting.leftSideBearing 左边距
* @param {number=} setting.rightSideBearing 右边距
* @param {number=} setting.verticalAlign 垂直对齐
* @return {Array} 改变的glyf
*/
}, {
key: "adjustGlyfPos",
value: function adjustGlyfPos(indexList, setting) {
var glyfList = this.getGlyf(indexList);
return adjustPos(glyfList, setting.leftSideBearing, setting.rightSideBearing, setting.verticalAlign);
}
/**
* 调整glyf
*
* @param {Array=} indexList 索引列表
* @param {Object} setting 选项
* @param {boolean=} setting.reverse 字形反转操作
* @param {boolean=} setting.mirror 字形镜像操作
* @param {number=} setting.scale 字形缩放
* @param {boolean=} setting.adjustToEmBox 是否调整字形到 em
* @param {number=} setting.adjustToEmPadding 调整到 em 框的留白
* @return {boolean}
*/
}, {
key: "adjustGlyf",
value: function adjustGlyf(indexList, setting) {
var glyfList = this.getGlyf(indexList);
var changed = false;
setting.adjustToEmBox = setting.ajdustToEmBox || setting.adjustToEmBox;
setting.adjustToEmPadding = setting.ajdustToEmPadding || setting.adjustToEmPadding;
if (setting.reverse || setting.mirror) {
changed = true;
glyfList.forEach(function (g) {
if (g.contours && g.contours.length) {
var offsetX = g.xMax + g.xMin;
var offsetY = g.yMax + g.yMin;
g.contours.forEach(function (contour) {
(0, _pathAdjust.default)(contour, setting.mirror ? -1 : 1, setting.reverse ? -1 : 1);
(0, _pathAdjust.default)(contour, 1, 1, setting.mirror ? offsetX : 0, setting.reverse ? offsetY : 0);
});
}
});
}
if (setting.scale && setting.scale !== 1) {
changed = true;
var scale = setting.scale;
glyfList.forEach(function (g) {
if (g.contours && g.contours.length) {
(0, _glyfAdjust.default)(g, scale, scale);
}
});
}
// 缩放到embox
else if (setting.adjustToEmBox) {
changed = true;
var ascent = this.ttf.hhea.ascent;
var descent = this.ttf.hhea.descent;
var adjustToEmPadding = 2 * (setting.adjustToEmPadding || 0);
adjustToEmBox(glyfList, ascent, descent, adjustToEmPadding);
}
return changed ? glyfList : [];
}
/**
* 获取glyf列表
*
* @param {Array=} indexList 索引列表
* @return {Array} glyflist
*/
}, {
key: "getGlyf",
value: function getGlyf(indexList) {
var glyf = this.ttf.glyf;
if (indexList && indexList.length) {
return indexList.map(function (item) {
return glyf[item];
});
}
return glyf;
}
/**
* 查找相关字形
*
* @param {Object} condition 查询条件
* @param {Array|number} condition.unicode unicode编码列表或者单个unicode编码
* @param {string} condition.name glyf名字例如`uniE001`, `uniE`
* @param {Function} condition.filter 自定义过滤器
* @example
* condition.filter = function (glyf) {
* return glyf.name === 'logo';
* }
* @return {Array} glyf字形索引列表
*/
}, {
key: "findGlyf",
value: function findGlyf(condition) {
if (!condition) {
return [];
}
var filters = [];
// 按unicode数组查找
if (condition.unicode) {
var unicodeList = Array.isArray(condition.unicode) ? condition.unicode : [condition.unicode];
var unicodeHash = {};
unicodeList.forEach(function (unicode) {
if (typeof unicode === 'string') {
unicode = Number('0x' + unicode.slice(1));
}
unicodeHash[unicode] = true;
});
filters.push(function (glyf) {
if (!glyf.unicode || !glyf.unicode.length) {
return false;
}
for (var i = 0, l = glyf.unicode.length; i < l; i++) {
if (unicodeHash[glyf.unicode[i]]) {
return true;
}
}
});
}
// 按名字查找
if (condition.name) {
var name = condition.name;
filters.push(function (glyf) {
return glyf.name && glyf.name.indexOf(name) === 0;
});
}
// 按筛选函数查找
if (typeof condition.filter === 'function') {
filters.push(condition.filter);
}
var indexList = [];
this.ttf.glyf.forEach(function (glyf, index) {
for (var filterIndex = 0, filter; filter = filters[filterIndex++];) {
if (true === filter(glyf)) {
indexList.push(index);
break;
}
}
});
return indexList;
}
/**
* 更新指定的glyf
*
* @param {Object} glyf glyfobject
* @param {string} index 需要替换的索引列表
* @return {Array} 改变的glyf
*/
}, {
key: "replaceGlyf",
value: function replaceGlyf(glyf, index) {
if (index >= 0 && index < this.ttf.glyf.length) {
this.ttf.glyf[index] = glyf;
return [glyf];
}
return [];
}
/**
* 设置glyf
*
* @param {Array} glyfList glyf列表
* @return {Array} 设置的glyf列表
*/
}, {
key: "setGlyf",
value: function setGlyf(glyfList) {
delete this.glyf;
this.ttf.glyf = glyfList || [];
return this.ttf.glyf;
}
/**
* 对字形按照unicode编码排序此处不对复合字形进行排序如果存在复合字形, 不进行排序
*
* @param {Array} glyfList glyf列表
* @return {Array} 设置的glyf列表
*/
}, {
key: "sortGlyf",
value: function sortGlyf() {
var glyf = this.ttf.glyf;
if (glyf.length > 1) {
// 如果存在复合字形则退出
if (glyf.some(function (a) {
return a.compound;
})) {
return -2;
}
var notdef = glyf.shift();
// 按代码点排序, 首先将空字形排到最后然后按照unicode第一个编码进行排序
glyf.sort(function (a, b) {
if ((!a.unicode || !a.unicode.length) && (!b.unicode || !b.unicode.length)) {
return 0;
} else if ((!a.unicode || !a.unicode.length) && b.unicode) {
return 1;
} else if (a.unicode && (!b.unicode || !b.unicode.length)) {
return -1;
}
return Math.min.apply(null, a.unicode) - Math.min.apply(null, b.unicode);
});
glyf.unshift(notdef);
return glyf;
}
return -1;
}
/**
* 设置名字
*
* @param {string} name 名字字段
* @return {Object} 名字对象
*/
}, {
key: "setName",
value: function setName(name) {
if (name) {
this.ttf.name.fontFamily = this.ttf.name.fullName = name.fontFamily || _default.default.name.fontFamily;
this.ttf.name.fontSubFamily = name.fontSubFamily || _default.default.name.fontSubFamily;
this.ttf.name.uniqueSubFamily = name.uniqueSubFamily || '';
this.ttf.name.postScriptName = name.postScriptName || '';
}
return this.ttf.name;
}
/**
* 设置head信息
*
* @param {Object} head 头部信息
* @return {Object} 头对象
*/
}, {
key: "setHead",
value: function setHead(head) {
if (head) {
// unitsperem
if (head.unitsPerEm && head.unitsPerEm >= 64 && head.unitsPerEm <= 16384) {
this.ttf.head.unitsPerEm = head.unitsPerEm;
}
// lowestrecppem
if (head.lowestRecPPEM && head.lowestRecPPEM >= 8 && head.lowestRecPPEM <= 16384) {
this.ttf.head.lowestRecPPEM = head.lowestRecPPEM;
}
// created
if (head.created) {
this.ttf.head.created = head.created;
}
if (head.modified) {
this.ttf.head.modified = head.modified;
}
}
return this.ttf.head;
}
/**
* 设置hhea信息
*
* @param {Object} fields 字段值
* @return {Object} 头对象
*/
}, {
key: "setHhea",
value: function setHhea(fields) {
(0, _lang.overwrite)(this.ttf.hhea, fields, ['ascent', 'descent', 'lineGap']);
return this.ttf.hhea;
}
/**
* 设置OS2信息
*
* @param {Object} fields 字段值
* @return {Object} 头对象
*/
}, {
key: "setOS2",
value: function setOS2(fields) {
(0, _lang.overwrite)(this.ttf['OS/2'], fields, ['usWinAscent', 'usWinDescent', 'sTypoAscender', 'sTypoDescender', 'sTypoLineGap', 'sxHeight', 'bXHeight', 'usWeightClass', 'usWidthClass', 'yStrikeoutPosition', 'yStrikeoutSize', 'achVendID',
// panose
'bFamilyType', 'bSerifStyle', 'bWeight', 'bProportion', 'bContrast', 'bStrokeVariation', 'bArmStyle', 'bLetterform', 'bMidline', 'bXHeight']);
return this.ttf['OS/2'];
}
/**
* 设置post信息
*
* @param {Object} fields 字段值
* @return {Object} 头对象
*/
}, {
key: "setPost",
value: function setPost(fields) {
(0, _lang.overwrite)(this.ttf.post, fields, ['underlinePosition', 'underlineThickness']);
return this.ttf.post;
}
/**
* 计算度量信息
*
* @return {Object} 度量信息
*/
}, {
key: "calcMetrics",
value: function calcMetrics() {
var ascent = -16384;
var descent = 16384;
var uX = 0x78;
var uH = 0x48;
var sxHeight;
var sCapHeight;
this.ttf.glyf.forEach(function (g) {
if (g.yMax > ascent) {
ascent = g.yMax;
}
if (g.yMin < descent) {
descent = g.yMin;
}
if (g.unicode) {
if (g.unicode.indexOf(uX) >= 0) {
sxHeight = g.yMax;
}
if (g.unicode.indexOf(uH) >= 0) {
sCapHeight = g.yMax;
}
}
});
ascent = Math.round(ascent);
descent = Math.round(descent);
return {
// 此处非必须自动设置
ascent: ascent,
descent: descent,
sTypoAscender: ascent,
sTypoDescender: descent,
// 自动设置项目
usWinAscent: ascent,
usWinDescent: -descent,
sxHeight: sxHeight || 0,
sCapHeight: sCapHeight || 0
};
}
/**
* 优化ttf字形信息
*
* @return {Array} 改变的glyf
*/
}, {
key: "optimize",
value: function optimize() {
return (0, _optimizettf.default)(this.ttf);
}
/**
* 复合字形转简单字形
*
* @param {Array=} indexList 索引列表
* @return {Array} 改变的glyf
*/
}, {
key: "compound2simple",
value: function compound2simple(indexList) {
var ttf = this.ttf;
if (ttf.maxp && !ttf.maxp.maxComponentElements) {
return [];
}
var i;
var l;
// 全部的compound glyf
if (!indexList || !indexList.length) {
indexList = [];
for (i = 0, l = ttf.glyf.length; i < l; ++i) {
if (ttf.glyf[i].compound) {
indexList.push(i);
}
}
}
var list = [];
for (i = 0, l = indexList.length; i < l; ++i) {
var glyfIndex = indexList[i];
if (ttf.glyf[glyfIndex] && ttf.glyf[glyfIndex].compound) {
(0, _compound2simpleglyf.default)(glyfIndex, ttf, true);
list.push(ttf.glyf[glyfIndex]);
}
}
return list;
}
}]);
}();

View File

@ -0,0 +1,22 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = ttf2base64;
var _bytes2base = _interopRequireDefault(require("./util/bytes2base64"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file ttf数组转base64编码
* @author mengke01(kekee000@gmail.com)
*/
/**
* ttf数组转base64编码
*
* @param {Array} arrayBuffer ArrayBuffer对象
* @return {string} base64编码
*/
function ttf2base64(arrayBuffer) {
return 'data:font/ttf;charset=utf-8;base64,' + (0, _bytes2base.default)(arrayBuffer);
}

View File

@ -0,0 +1,124 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = ttf2eot;
var _reader = _interopRequireDefault(require("./reader"));
var _writer = _interopRequireDefault(require("./writer"));
var _string = _interopRequireDefault(require("./util/string"));
var _error = _interopRequireDefault(require("./error"));
var _table = _interopRequireDefault(require("./table/table"));
var _struct = _interopRequireDefault(require("./table/struct"));
var _name = _interopRequireDefault(require("./table/name"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file ttf转eot
* @author mengke01(kekee000@gmail.com)
*
* reference:
* http://www.w3.org/Submission/EOT/
* https://github.com/fontello/ttf2eot/blob/master/index.js
*/
var EotHead = _table.default.create('head', [['EOTSize', _struct.default.Uint32], ['FontDataSize', _struct.default.Uint32], ['Version', _struct.default.Uint32], ['Flags', _struct.default.Uint32], ['PANOSE', _struct.default.Bytes, 10], ['Charset', _struct.default.Uint8], ['Italic', _struct.default.Uint8], ['Weight', _struct.default.Uint32], ['fsType', _struct.default.Uint16], ['MagicNumber', _struct.default.Uint16], ['UnicodeRange', _struct.default.Bytes, 16], ['CodePageRange', _struct.default.Bytes, 8], ['CheckSumAdjustment', _struct.default.Uint32], ['Reserved', _struct.default.Bytes, 16], ['Padding1', _struct.default.Uint16]]);
/**
* ttf格式转换成eot字体格式
*
* @param {ArrayBuffer} ttfBuffer ttf缓冲数组
* @param {Object} options 选项
* @return {ArrayBuffer} eot格式byte流
*/
// eslint-disable-next-line no-unused-vars
function ttf2eot(ttfBuffer) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
// 构造eot头部
var eotHead = new EotHead();
var eotHeaderSize = eotHead.size();
var eot = {};
eot.head = eotHead.read(new _reader.default(new ArrayBuffer(eotHeaderSize)));
// set fields
eot.head.FontDataSize = ttfBuffer.byteLength || ttfBuffer.length;
eot.head.Version = 0x20001;
eot.head.Flags = 0;
eot.head.Charset = 0x1;
eot.head.MagicNumber = 0x504C;
eot.head.Padding1 = 0;
var ttfReader = new _reader.default(ttfBuffer);
// 读取ttf表个数
var numTables = ttfReader.readUint16(4);
if (numTables <= 0 || numTables > 100) {
_error.default.raise(10101);
}
// 读取ttf表索引信息
ttfReader.seek(12);
// 需要读取3个表内容设置3个byte
var tblReaded = 0;
for (var i = 0; i < numTables && tblReaded !== 0x7; ++i) {
var tableEntry = {
tag: ttfReader.readString(ttfReader.offset, 4),
checkSum: ttfReader.readUint32(),
offset: ttfReader.readUint32(),
length: ttfReader.readUint32()
};
var entryOffset = ttfReader.offset;
if (tableEntry.tag === 'head') {
eot.head.CheckSumAdjustment = ttfReader.readUint32(tableEntry.offset + 8);
tblReaded += 0x1;
} else if (tableEntry.tag === 'OS/2') {
eot.head.PANOSE = ttfReader.readBytes(tableEntry.offset + 32, 10);
eot.head.Italic = ttfReader.readUint16(tableEntry.offset + 62);
eot.head.Weight = ttfReader.readUint16(tableEntry.offset + 4);
eot.head.fsType = ttfReader.readUint16(tableEntry.offset + 8);
eot.head.UnicodeRange = ttfReader.readBytes(tableEntry.offset + 42, 16);
eot.head.CodePageRange = ttfReader.readBytes(tableEntry.offset + 78, 8);
tblReaded += 0x2;
}
// 设置名字信息
else if (tableEntry.tag === 'name') {
var names = new _name.default(tableEntry.offset).read(ttfReader);
eot.FamilyName = _string.default.toUCS2Bytes(names.fontFamily || '');
eot.FamilyNameSize = eot.FamilyName.length;
eot.StyleName = _string.default.toUCS2Bytes(names.fontStyle || '');
eot.StyleNameSize = eot.StyleName.length;
eot.VersionName = _string.default.toUCS2Bytes(names.version || '');
eot.VersionNameSize = eot.VersionName.length;
eot.FullName = _string.default.toUCS2Bytes(names.fullName || '');
eot.FullNameSize = eot.FullName.length;
tblReaded += 0x3;
}
ttfReader.seek(entryOffset);
}
// 计算size
eot.head.EOTSize = eotHeaderSize + 4 + eot.FamilyNameSize + 4 + eot.StyleNameSize + 4 + eot.VersionNameSize + 4 + eot.FullNameSize + 2 + eot.head.FontDataSize;
// 这里用小尾方式写入
var eotWriter = new _writer.default(new ArrayBuffer(eot.head.EOTSize), 0, eot.head.EOTSize, true);
// write head
eotHead.write(eotWriter, eot);
// write names
eotWriter.writeUint16(eot.FamilyNameSize);
eotWriter.writeBytes(eot.FamilyName, eot.FamilyNameSize);
eotWriter.writeUint16(0);
eotWriter.writeUint16(eot.StyleNameSize);
eotWriter.writeBytes(eot.StyleName, eot.StyleNameSize);
eotWriter.writeUint16(0);
eotWriter.writeUint16(eot.VersionNameSize);
eotWriter.writeBytes(eot.VersionName, eot.VersionNameSize);
eotWriter.writeUint16(0);
eotWriter.writeUint16(eot.FullNameSize);
eotWriter.writeBytes(eot.FullName, eot.FullNameSize);
eotWriter.writeUint16(0);
// write rootstring
eotWriter.writeUint16(0);
eotWriter.writeBytes(ttfBuffer, eot.head.FontDataSize);
return eotWriter.getBuffer();
}

Some files were not shown because too many files have changed in this diff Show More