add woff2ttf modify import
This commit is contained in:
55
demo/js/woff2ttf.js
Normal file
55
demo/js/woff2ttf.js
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* @file woff2ttf.js
|
||||
* @author mengke01
|
||||
* @date
|
||||
* @description
|
||||
* woff 转ttf
|
||||
*/
|
||||
|
||||
define(
|
||||
function(require) {
|
||||
var ajaxBinaryFile = require('common/ajaxBinaryFile');
|
||||
var woff2ttf = require('ttf/woff2ttf');
|
||||
var TTFReader = require('ttf/ttfreader');
|
||||
var inflate = require('inflate').inflate;
|
||||
var ttf2base64 = require('ttf/ttf2base64');
|
||||
|
||||
function write() {
|
||||
|
||||
ajaxBinaryFile({
|
||||
url: '../font/iconfont.woff',
|
||||
onSuccess: function(buffer) {
|
||||
|
||||
var ttfBuffer = woff2ttf(buffer, {
|
||||
inflate: inflate
|
||||
});
|
||||
|
||||
var saveBtn = $('.saveas');
|
||||
saveBtn.attr('href', ttf2base64(ttfBuffer));
|
||||
saveBtn.attr('download', 'save.woff');
|
||||
|
||||
var ttfReader = new TTFReader();
|
||||
var ttfData = ttfReader.read(ttfBuffer);
|
||||
console.log(ttfData);
|
||||
},
|
||||
onError: function() {
|
||||
console.error('error read file');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var entry = {
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
init: function () {
|
||||
write();
|
||||
}
|
||||
};
|
||||
|
||||
entry.init();
|
||||
|
||||
return entry;
|
||||
}
|
||||
);
|
||||
29
demo/woff2ttf.html
Normal file
29
demo/woff2ttf.html
Normal file
@@ -0,0 +1,29 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>woff2ttf</title>
|
||||
<script src="../dep/esl.js"></script>
|
||||
<script src="../dep/jquery.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<a class="saveas" href="" download="">保存</a>
|
||||
|
||||
<script>
|
||||
require.config({
|
||||
baseUrl: '../src',
|
||||
paths: {
|
||||
demo: '../demo/js',
|
||||
inflate: '../dep/pako_inflate.min'
|
||||
}
|
||||
});
|
||||
define('jquery', $);
|
||||
</script>
|
||||
|
||||
<script>
|
||||
require(['demo/woff2ttf']);
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
2
dep/pako_inflate.min.js
vendored
Normal file
2
dep/pako_inflate.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -11,18 +11,22 @@ define(
|
||||
|
||||
var program = require('../program');
|
||||
var TTFReader = require('ttf/ttfreader');
|
||||
var contours2svg = require('ttf/util/contours2svg');
|
||||
var glyf2svg = require('ttf/util/glyf2svg');
|
||||
var svg2ttfobject = require('ttf/svg2ttfobject');
|
||||
var string = require('common/string');
|
||||
var pathAdjust = require('graphics/pathAdjust');
|
||||
var TTFWriter = require('ttf/ttfwriter');
|
||||
var ttf2woff = require('ttf/ttf2woff');
|
||||
var woff2ttf = require('ttf/woff2ttf');
|
||||
var ttf2base64 = require('ttf/ttf2base64');
|
||||
var woff2base64 = require('ttf/woff2base64');
|
||||
|
||||
var woffOptions = {
|
||||
inflate: require('inflate').inflate
|
||||
};
|
||||
|
||||
var GLYF_ITEM_TPL = ''
|
||||
+ '<div class="glyf-item ${modify}">'
|
||||
+ '<div data-index="${index}" class="glyf-item ${modify}">'
|
||||
+ '<svg class="glyf" viewbox="0 0 ${unitsPerEm} ${unitsPerEm}"><g transform="scale(1, -1) translate(0, -${descent}) scale(0.95, 0.95) "><path class="path" ${d}/></g></svg>'
|
||||
+ '<div class="unicode" title="${unicode}">${unicode}</div><div class="name" title="${name}">${name}</div>'
|
||||
+ '</div>';
|
||||
@@ -35,7 +39,7 @@ define(
|
||||
$('#font-import').click();
|
||||
},
|
||||
export: function() {
|
||||
$(this).attr('href', '#');
|
||||
//$(this).attr('href', '#');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -43,18 +47,23 @@ define(
|
||||
function showGLYF(ttf) {
|
||||
var unitsPerEm = ttf.head.unitsPerEm;
|
||||
var descent = unitsPerEm + ttf.hhea.descent;
|
||||
var glyfStr = '';
|
||||
ttf.glyf.forEach(function(glyf) {
|
||||
var glyfStr = '', d = '';
|
||||
ttf.glyf.forEach(function(glyf, index) {
|
||||
var g = {
|
||||
index: index,
|
||||
modify: glyf.modify,
|
||||
unitsPerEm: unitsPerEm,
|
||||
descent: descent,
|
||||
unicode: (glyf.unicode || []).map(function(u) {
|
||||
return '$' + u.toString(16).toUpperCase();
|
||||
}).join(','),
|
||||
name: glyf.name,
|
||||
d: glyf.contours && glyf.contours.length ? 'd="'+ contours2svg(glyf.contours) +'"': ''
|
||||
name: glyf.name
|
||||
};
|
||||
|
||||
if (d = glyf2svg(glyf, ttf)) {
|
||||
g.d = 'd="'+ d +'"';
|
||||
}
|
||||
|
||||
glyfStr += string.format(GLYF_ITEM_TPL, g);
|
||||
});
|
||||
|
||||
@@ -62,11 +71,16 @@ define(
|
||||
}
|
||||
|
||||
// 加载ttf
|
||||
function loadTTF(file) {
|
||||
function loadSFNT(file, type) {
|
||||
program.loading.show();
|
||||
var fileReader = new FileReader();
|
||||
fileReader.onload = function(e) {
|
||||
var buffer = e.target.result;
|
||||
|
||||
if (type == 'woff') {
|
||||
buffer = woff2ttf(buffer, woffOptions);
|
||||
}
|
||||
|
||||
var ttfReader = new TTFReader();
|
||||
program.data.ttf = ttfReader.read(buffer);
|
||||
showGLYF(program.data.ttf);
|
||||
@@ -127,9 +141,9 @@ define(
|
||||
function onUpFile(e) {
|
||||
var file = e.target.files[0];
|
||||
|
||||
if (program.action == 'open' && file.name.match(/\.ttf$/)) {
|
||||
if (program.action == 'open' && file.name.match(/(\.ttf|\.woff)$/)) {
|
||||
program.data.file = file.name;
|
||||
loadTTF(file);
|
||||
loadSFNT(file, file.name.slice(file.name.lastIndexOf('.') + 1));
|
||||
}
|
||||
else if (program.action == 'svg' && file.name.match(/\.svg$/)) {
|
||||
if (program.data.ttf) {
|
||||
@@ -149,8 +163,9 @@ define(
|
||||
var ttf = program.data.ttf;
|
||||
if (ttf) {
|
||||
var buffer = new TTFWriter().write(ttf);
|
||||
e.target.download = (ttf.name.fontFamily || 'export') + '.ttf';
|
||||
e.target.href = ttf2base64(buffer);
|
||||
var target = $(e.target);
|
||||
target.attr('download', (ttf.name.fontFamily || 'export') + '.ttf');
|
||||
target.attr('href', ttf2base64(buffer));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ define(
|
||||
ttf.head.xMax = Math.round(ttf.head.xMax);
|
||||
ttf.head.yMin = Math.round(ttf.head.yMin);
|
||||
ttf.head.yMax = Math.round(ttf.head.yMax);
|
||||
ttf.head.unitsPerEm = Math.round(ttf.head.unitsPerEm || 1024);
|
||||
ttf.head.unitsPerEm = ttf.head.unitsPerEm ? Math.round(ttf.head.unitsPerEm) : 0;
|
||||
|
||||
return ttf;
|
||||
}
|
||||
@@ -148,6 +148,14 @@ define(
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有定义unitsPerEm,可以用viewBox代替
|
||||
if (!ttf.head.unitsPerEm && svgNode.getAttribute('viewBox')) {
|
||||
var bound = svgNode.getAttribute('viewBox').split(' ');
|
||||
if (bound.length == 4) {
|
||||
ttf.head.unitsPerEm = +bound[2];
|
||||
}
|
||||
}
|
||||
|
||||
// 解析glyf
|
||||
var d, unicode;
|
||||
if (missingNode) {
|
||||
|
||||
@@ -19,7 +19,6 @@ define(
|
||||
function(require) {
|
||||
var Reader = require('./reader');
|
||||
var Writer = require('./writer');
|
||||
var checkSum = require('./util/checkSum');
|
||||
var string = require('common/string');
|
||||
|
||||
/**
|
||||
@@ -134,6 +133,7 @@ define(
|
||||
* @param {ArrayBuffer} ttfBuffer ttf缓冲数组
|
||||
* @param {Object} options 选项
|
||||
* @param {Object} options.metadata 字体相关的信息
|
||||
* @param {Object} options.deflate 压缩相关函数
|
||||
*
|
||||
* @return {ArrayBuffer} woff格式byte流
|
||||
*/
|
||||
|
||||
@@ -14,8 +14,10 @@
|
||||
define(
|
||||
function(require) {
|
||||
var contour2svg = require('./contour2svg');
|
||||
var contours2svg = require('./contours2svg');
|
||||
var pathAdjust = require('graphics/pathAdjust');
|
||||
var matrixTransform = require('graphics/transform');
|
||||
var lang = require('common/lang');
|
||||
|
||||
/**
|
||||
* glyf转换svg
|
||||
@@ -23,29 +25,25 @@ define(
|
||||
* @param {Object} glyf 解析后的glyf结构
|
||||
* @return {string} svg文本
|
||||
*/
|
||||
function glyf2svg(glyf, options) {
|
||||
if(!glyf) {
|
||||
return null;
|
||||
}
|
||||
var pathArray = [];
|
||||
var contours = glyf.contours;
|
||||
var height = glyf.yMax;
|
||||
var x = options.x || 0;
|
||||
var y = height + (options.y || 0);
|
||||
var scale = options.scale || 1;
|
||||
function glyf2svg(glyf, ttf) {
|
||||
|
||||
if(!glyf) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var pathArray = [];
|
||||
|
||||
if (!glyf.compound) {
|
||||
for ( var i = 0, l = contours.length; i < l; i++) {
|
||||
pathAdjust(contours[i], 1, -1);
|
||||
pathAdjust(contours[i], scale, scale, x, y);
|
||||
pathArray.push(contour2svg(contours[i]));
|
||||
if (glyf.contours && glyf.contours.length) {
|
||||
pathArray.push(contours2svg(glyf.contours));
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
var glyfs = glyf.glyfs;
|
||||
glyfs.forEach(function(g) {
|
||||
var contours = g.glyf.contours;
|
||||
var compound = ttf.glyf[g.glyphIndex];
|
||||
var contours = lang.clone(compound.contours); // 这里需要进行matrix变换,需要复制一份
|
||||
var transform = g.transform;
|
||||
for ( var i = 0, l = contours.length; i < l; i++) {
|
||||
matrixTransform(contours[i],
|
||||
@@ -56,8 +54,6 @@ define(
|
||||
transform.e,
|
||||
transform.f
|
||||
);
|
||||
pathAdjust(contours[i], 1, -1);
|
||||
pathAdjust(contours[i], scale, scale, x, y);
|
||||
pathArray.push(contour2svg(contours[i]));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -71,9 +71,10 @@ define(
|
||||
|
||||
// 获取segments
|
||||
var segments = [];
|
||||
var cmd, lastIndex, args, segReg = /\-?\d+(?:\.\d+)?\b/g;
|
||||
var cmd, relative = false, c, r, lastIndex, args, segReg = /\-?\d+(?:\.\d+)?\b/g;
|
||||
for (var i = 0, l = path.length;i < l; i++) {
|
||||
var c = path.charAt(i).toUpperCase();
|
||||
c = path[i].toUpperCase();
|
||||
r = c != path[i];
|
||||
switch (c) {
|
||||
case 'M':
|
||||
if (i == 0) {
|
||||
@@ -97,6 +98,7 @@ define(
|
||||
args = path.slice(lastIndex, i);
|
||||
segments.push({
|
||||
cmd: cmd,
|
||||
relative: relative,
|
||||
args: args.match(segReg).map(function(d) {
|
||||
return +d.trim();
|
||||
})
|
||||
@@ -104,6 +106,7 @@ define(
|
||||
}
|
||||
|
||||
cmd = c;
|
||||
relative = r;
|
||||
lastIndex = i + 1;
|
||||
break;
|
||||
}
|
||||
@@ -115,39 +118,86 @@ define(
|
||||
var contours = [], contour = [], prevX = 0, prevY = 0, prevc1;
|
||||
for (var i = 0, l = segments.length;i < l; i++) {
|
||||
segment = segments[i];
|
||||
cmd = segment.cmd;
|
||||
relative = segment.relative;
|
||||
|
||||
if (segment.cmd === 'Z') {
|
||||
if (cmd === 'Z') {
|
||||
contours.push(contour);
|
||||
contour = [];
|
||||
}
|
||||
else if (segment.cmd === 'M') {
|
||||
prevX = segment.args[0];
|
||||
prevY = segment.args[1];
|
||||
else if (cmd === 'M') {
|
||||
if (relative) {
|
||||
prevX += segment.args[0];
|
||||
prevY += segment.args[1];
|
||||
}
|
||||
else {
|
||||
prevX = segment.args[0];
|
||||
prevY = segment.args[1];
|
||||
}
|
||||
|
||||
contour.push({
|
||||
x: prevX,
|
||||
y: prevY,
|
||||
onCurve: true
|
||||
});
|
||||
}
|
||||
else if (segment.cmd === 'H') {
|
||||
prevX += segment.args[0];
|
||||
else if (cmd === 'H') {
|
||||
|
||||
if (relative) {
|
||||
prevX += segment.args[0];
|
||||
}
|
||||
else {
|
||||
prevX = segment.args[0];
|
||||
}
|
||||
|
||||
contour.push({
|
||||
x: prevX,
|
||||
y: prevY,
|
||||
onCurve: true
|
||||
});
|
||||
}
|
||||
else if (segment.cmd === 'V') {
|
||||
prevY += segment.args[0];
|
||||
else if (cmd === 'V') {
|
||||
|
||||
if (relative) {
|
||||
prevY += segment.args[0];
|
||||
}
|
||||
else {
|
||||
prevY = segment.args[0];
|
||||
}
|
||||
|
||||
contour.push({
|
||||
x: prevX,
|
||||
y: prevY,
|
||||
onCurve: true
|
||||
});
|
||||
}
|
||||
else if (segment.cmd === 'L') {
|
||||
prevX += segment.args[0];
|
||||
prevY += segment.args[1];
|
||||
else if (cmd === 'L') {
|
||||
|
||||
// 这里可能会连续绘制,最后一个是终点
|
||||
var q = 0, ql = segment.args.length - 2, px = 0, py = 0;
|
||||
|
||||
if (relative) {
|
||||
px = prevX;
|
||||
py = prevY;
|
||||
}
|
||||
|
||||
for (; q < ql ; q += 2) {
|
||||
contour.push({
|
||||
x: px + segment.args[q],
|
||||
y: py + segment.args[q + 1],
|
||||
onCurve: true
|
||||
});
|
||||
}
|
||||
|
||||
if (relative) {
|
||||
prevX += segment.args[ql];
|
||||
prevY += segment.args[ql + 1];
|
||||
}
|
||||
else {
|
||||
prevX = segment.args[ql];
|
||||
prevY = segment.args[ql + 1];
|
||||
}
|
||||
|
||||
contour.push({
|
||||
x: prevX,
|
||||
y: prevY,
|
||||
@@ -155,40 +205,78 @@ define(
|
||||
});
|
||||
}
|
||||
// 二次贝塞尔
|
||||
else if (segment.cmd === 'Q') {
|
||||
else if (cmd === 'Q') {
|
||||
// 这里可能会连续绘制,最后一个是终点
|
||||
var q = 0, ql = segment.args.length - 2;
|
||||
for (; q < ql ; q += 2) {
|
||||
var q = 0, ql = segment.args.length, px = 0, py = 0;
|
||||
|
||||
if (relative) {
|
||||
px = prevX;
|
||||
py = prevY;
|
||||
}
|
||||
|
||||
for (; q < ql ; q += 4) {
|
||||
contour.push({
|
||||
x: prevX + segment.args[q],
|
||||
y: prevY + segment.args[q + 1]
|
||||
x: px + segment.args[q],
|
||||
y: py + segment.args[q + 1]
|
||||
});
|
||||
contour.push({
|
||||
x: px + segment.args[q + 2],
|
||||
y: py + segment.args[q + 3],
|
||||
onCurve: true
|
||||
});
|
||||
}
|
||||
|
||||
prevX += segment.args[ql];
|
||||
prevY += segment.args[ql + 1];
|
||||
|
||||
contour.push({
|
||||
x: prevX,
|
||||
y: prevY,
|
||||
onCurve: true
|
||||
});
|
||||
ql = segment.args.length - 2;
|
||||
if (relative) {
|
||||
prevX += segment.args[ql];
|
||||
prevY += segment.args[ql + 1];
|
||||
}
|
||||
else {
|
||||
prevX = segment.args[ql];
|
||||
prevY = segment.args[ql + 1];
|
||||
}
|
||||
}
|
||||
// 二次贝塞尔平滑
|
||||
else if (segment.cmd === 'T') {
|
||||
else if (cmd === 'T') {
|
||||
|
||||
var pc = contour[contour.length - 2];
|
||||
|
||||
// 这里需要移除上一个曲线的终点
|
||||
contour.pop();
|
||||
var last = contour.pop();
|
||||
|
||||
var pc = contour[contour.length - 1];
|
||||
|
||||
contour.push({
|
||||
x: 2 * prevX - pc.x,
|
||||
y: 2 * prevY - pc.y
|
||||
x: 2 * last.x - pc.x,
|
||||
y: 2 * last.y - pc.y
|
||||
});
|
||||
|
||||
prevX += segment.args[0];
|
||||
prevY += segment.args[1];
|
||||
var q = 0, ql = segment.args.length - 2, px = 0, py = 0;
|
||||
|
||||
if (relative) {
|
||||
px = prevX;
|
||||
py = prevY;
|
||||
}
|
||||
|
||||
for (; q < ql ; q += 2) {
|
||||
pc = contour[contour.length - 1];
|
||||
last = {
|
||||
x: px + segment.args[q],
|
||||
y: py + segment.args[q + 1]
|
||||
};
|
||||
contour.push({
|
||||
x: 2 * last.x - pc.x,
|
||||
y: 2 * last.y - pc.y
|
||||
});
|
||||
}
|
||||
|
||||
if (relative) {
|
||||
prevX += segment.args[ql];
|
||||
prevY += segment.args[ql + 1];
|
||||
}
|
||||
else {
|
||||
prevX = segment.args[ql];
|
||||
prevY = segment.args[ql + 1];
|
||||
}
|
||||
|
||||
contour.push({
|
||||
x: prevX,
|
||||
y: prevY,
|
||||
@@ -197,21 +285,26 @@ define(
|
||||
|
||||
}
|
||||
// 三次贝塞尔
|
||||
else if (segment.cmd === 'C') {
|
||||
else if (cmd === 'C') {
|
||||
|
||||
// 这里可能会连续绘制,最后一个是终点
|
||||
var q = 0, ql = segment.args.length - 2;
|
||||
var q = 0, ql = segment.args.length - 2, px = 0, py = 0;
|
||||
var cubicList = [];
|
||||
|
||||
if (relative) {
|
||||
px = prevX;
|
||||
py = prevY;
|
||||
}
|
||||
|
||||
for (; q < ql ; q += 4) {
|
||||
var cubic = [];
|
||||
var c1 = {
|
||||
x: prevX + segment.args[q],
|
||||
y: prevY + segment.args[q + 1]
|
||||
x: px + segment.args[q],
|
||||
y: py + segment.args[q + 1]
|
||||
};
|
||||
var c2 = {
|
||||
x: prevX + segment.args[q + 2],
|
||||
y: prevY + segment.args[q + 3]
|
||||
x: px + segment.args[q + 2],
|
||||
y: py + segment.args[q + 3]
|
||||
};
|
||||
|
||||
// 计算中间点
|
||||
@@ -236,29 +329,53 @@ define(
|
||||
cubicList.push(cubic);
|
||||
}
|
||||
|
||||
prevX += segment.args[ql];
|
||||
prevY += segment.args[ql + 1];
|
||||
if (relative) {
|
||||
prevX += segment.args[ql];
|
||||
prevY += segment.args[ql + 1];
|
||||
}
|
||||
else {
|
||||
prevX = segment.args[ql];
|
||||
prevY = segment.args[ql + 1];
|
||||
}
|
||||
|
||||
cubicList[cubicList.length - 1].push({x: prevX, y: prevY});
|
||||
cubic2Points(cubicList, contour);
|
||||
prevc1 = cubicList[cubicList.length - 1][2];
|
||||
}
|
||||
// 三次贝塞尔平滑
|
||||
else if (segment.cmd === 'S') {
|
||||
else if (cmd === 'S') {
|
||||
|
||||
// TODO 这里没有支持连续的情况,有时间再搞
|
||||
if (segment.args.length > 4) {
|
||||
throw 'not support svg "S" command continuous!'
|
||||
}
|
||||
|
||||
// 这里需要移除上一个曲线的终点
|
||||
var p1 = contour.pop();
|
||||
var c1 = {
|
||||
x: 2 * p1.x - prevc1.x,
|
||||
y: 2 * p1.y - prevc1.y
|
||||
};
|
||||
|
||||
var px = 0, py = 0;
|
||||
|
||||
if (relative) {
|
||||
px = prevX;
|
||||
py = prevY;
|
||||
}
|
||||
var c2 = {
|
||||
x: prevX + segment.args[0],
|
||||
y: prevX + segment.args[1]
|
||||
x: px + segment.args[0],
|
||||
y: py + segment.args[1]
|
||||
};
|
||||
|
||||
prevX += segment.args[2];
|
||||
prevY += segment.args[3];
|
||||
if (relative) {
|
||||
prevX += segment.args[2];
|
||||
prevY += segment.args[3];
|
||||
}
|
||||
else {
|
||||
prevX = segment.args[2];
|
||||
prevY = segment.args[3];
|
||||
}
|
||||
|
||||
var p2 = {
|
||||
x: prevX,
|
||||
@@ -269,7 +386,7 @@ define(
|
||||
prevc1 = c2;
|
||||
}
|
||||
// 圆弧
|
||||
else if (segment.cmd === 'A') {
|
||||
else if (cmd === 'A') {
|
||||
throw 'not support arc';
|
||||
}
|
||||
}
|
||||
|
||||
122
src/ttf/woff2ttf.js
Normal file
122
src/ttf/woff2ttf.js
Normal file
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* @file woff2ttf.js
|
||||
* @author mengke01
|
||||
* @date
|
||||
* @description
|
||||
* woff转换ttf
|
||||
*/
|
||||
|
||||
|
||||
define(
|
||||
function(require) {
|
||||
|
||||
var Reader = require('./reader');
|
||||
var Writer = require('./writer');
|
||||
|
||||
/**
|
||||
* 写空数据
|
||||
*
|
||||
* @param {Writer} writer writer对象
|
||||
* @param {number} length 大小
|
||||
* @return {Writer}
|
||||
*/
|
||||
function writeEmpty(writer, length) {
|
||||
while (length-- > 0) {
|
||||
writer.writeUint8(0);
|
||||
}
|
||||
return writer;
|
||||
}
|
||||
|
||||
/**
|
||||
* woff格式转换成ttf字体格式
|
||||
*
|
||||
* @param {ArrayBuffer} woffBuffer ttf缓冲数组
|
||||
* @param {Object} options 选项
|
||||
* @param {Object} options.inflate 解压相关函数
|
||||
*
|
||||
* @return {ArrayBuffer} woff格式byte流
|
||||
*/
|
||||
function woff2ttf(woffBuffer, options) {
|
||||
options = options || {};
|
||||
|
||||
var reader = new Reader(woffBuffer);
|
||||
var signature = reader.readUint32(0);
|
||||
var flavor = reader.readUint32(4);
|
||||
|
||||
if (signature !== 0x774F4646 || flavor !== 0x10000) {
|
||||
reader.dispose();
|
||||
throw 'not a ttf sfnt format!';
|
||||
}
|
||||
|
||||
var numTables = reader.readUint16(12);
|
||||
var ttfSize = reader.readUint32(16);
|
||||
var tableEntries = [];
|
||||
|
||||
// 读取woff表索引信息
|
||||
for (var i = 0; i < numTables; ++i) {
|
||||
reader.seek(44 + i * 20);
|
||||
var tableEntry = {
|
||||
tag: reader.readString(reader.offset, 4),
|
||||
offset: reader.readUint32(),
|
||||
compLength: reader.readUint32(),
|
||||
length: reader.readUint32(),
|
||||
checkSum: reader.readUint32()
|
||||
};
|
||||
|
||||
// ttf 表数据
|
||||
var deflateData = reader.readBytes(tableEntry.offset, tableEntry.compLength);
|
||||
// 需要解压
|
||||
if (deflateData.length < tableEntry.length) {
|
||||
if (!options.inflate) {
|
||||
reader.dispose();
|
||||
throw 'no inflate function!';
|
||||
}
|
||||
tableEntry.data = options.inflate(deflateData);
|
||||
}
|
||||
else {
|
||||
tableEntry.data = deflateData;
|
||||
}
|
||||
tableEntry.length = tableEntry.data.length;
|
||||
|
||||
tableEntries.push(tableEntry);
|
||||
}
|
||||
|
||||
|
||||
var writer = new Writer(new ArrayBuffer(ttfSize));
|
||||
// 写头部
|
||||
var entrySelector = Math.floor(Math.log(numTables)/Math.LN2);
|
||||
var searchRange = Math.pow(2, entrySelector) * 16;
|
||||
var rangeShift = numTables * 16 - searchRange;
|
||||
writer.writeFixed(1);
|
||||
writer.writeUint16(numTables);
|
||||
writer.writeUint16(searchRange);
|
||||
writer.writeUint16(entrySelector);
|
||||
writer.writeUint16(rangeShift);
|
||||
|
||||
// 写ttf表索引
|
||||
var tblOffset = 12 + 16 * tableEntries.length;
|
||||
for (var i = 0, l = tableEntries.length; i < l; ++i) {
|
||||
var tableEntry = tableEntries[i];
|
||||
writer.writeString(tableEntry.tag);
|
||||
writer.writeUint32(tableEntry.checkSum);
|
||||
writer.writeUint32(tblOffset);
|
||||
writer.writeUint32(tableEntry.length);
|
||||
tblOffset += tableEntry.length + (tableEntry.length % 4 ? 4 - tableEntry.length % 4 : 0)
|
||||
}
|
||||
|
||||
// 写ttf表数据
|
||||
for (var i = 0, l = tableEntries.length; i < l; ++i) {
|
||||
var tableEntry = tableEntries[i];
|
||||
writer.writeBytes(tableEntry.data);
|
||||
if (tableEntry.length % 4) {
|
||||
writeEmpty(writer, 4 - tableEntry.length % 4);
|
||||
}
|
||||
}
|
||||
|
||||
return writer.getBuffer();
|
||||
}
|
||||
|
||||
|
||||
return woff2ttf;
|
||||
}
|
||||
);
|
||||
6
ttf.html
6
ttf.html
@@ -36,7 +36,11 @@
|
||||
<script src="./dep/bootstrap/js/bootstrap.min.js"></script>
|
||||
<script>
|
||||
require.config({
|
||||
baseUrl: './src'
|
||||
baseUrl: './src',
|
||||
paths: {
|
||||
deflate: '../dep/pako_deflate.min',
|
||||
inflate: '../dep/pako_inflate.min'
|
||||
}
|
||||
});
|
||||
define('jquery', $);
|
||||
require(['fonteditor/ttf/main'])
|
||||
|
||||
Reference in New Issue
Block a user