add compound glyf
This commit is contained in:
@@ -15,6 +15,7 @@ define(
|
|||||||
var ajaxBinaryFile = require('common/ajaxBinaryFile');
|
var ajaxBinaryFile = require('common/ajaxBinaryFile');
|
||||||
var setFontface = require('./setFontface');
|
var setFontface = require('./setFontface');
|
||||||
var glyf2canvas = require('ttf/util/glyf2canvas');
|
var glyf2canvas = require('ttf/util/glyf2canvas');
|
||||||
|
var lang = require('common/lang');
|
||||||
|
|
||||||
var ttf = null;
|
var ttf = null;
|
||||||
|
|
||||||
@@ -44,15 +45,8 @@ define(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function showGlyf(charcode) {
|
function showGlyf(charcode) {
|
||||||
var glyfData = ttf.getCodeGlyf(charcode);
|
|
||||||
|
var glyf = lang.clone(ttf.getCodeGlyf(charcode));
|
||||||
var glyf = {
|
|
||||||
xMin: glyfData.xMin,
|
|
||||||
xMax: glyfData.xMax,
|
|
||||||
yMin: glyfData.yMin,
|
|
||||||
yMax: glyfData.yMax,
|
|
||||||
contours: glyfData.contours
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
var canvas = $('#glyf-canvas').get(0);
|
var canvas = $('#glyf-canvas').get(0);
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ define(
|
|||||||
var ajaxBinaryFile = require('common/ajaxBinaryFile');
|
var ajaxBinaryFile = require('common/ajaxBinaryFile');
|
||||||
var glyf2svg = require('ttf/util/glyf2svg');
|
var glyf2svg = require('ttf/util/glyf2svg');
|
||||||
var setFontface = require('./setFontface');
|
var setFontface = require('./setFontface');
|
||||||
|
var lang = require('common/lang');
|
||||||
|
|
||||||
|
|
||||||
var ttf = null;
|
var ttf = null;
|
||||||
|
|
||||||
// 设置字体
|
// 设置字体
|
||||||
@@ -26,7 +29,7 @@ define(
|
|||||||
|
|
||||||
// 查看ttf glyf
|
// 查看ttf glyf
|
||||||
function showTTFGlyf(ttfData) {
|
function showTTFGlyf(ttfData) {
|
||||||
console.log(ttfData);
|
|
||||||
ttf = new TTF(ttfData);
|
ttf = new TTF(ttfData);
|
||||||
var codes = ttf.codes();
|
var codes = ttf.codes();
|
||||||
|
|
||||||
@@ -53,11 +56,10 @@ define(
|
|||||||
+ '</g>'
|
+ '</g>'
|
||||||
+ '</svg>';
|
+ '</svg>';
|
||||||
var svg = $(tpl);
|
var svg = $(tpl);
|
||||||
var glyf = ttf.getCodeGlyf(charcode);
|
var glyf = lang.clone(ttf.getCodeGlyf(charcode));
|
||||||
var lang = require('common/lang');
|
|
||||||
|
|
||||||
// 调整大小
|
// 调整大小
|
||||||
var width = glyf.xMax - glyf.xMin;
|
var width = glyf.xMax;
|
||||||
var height = glyf.yMax - glyf.yMin;
|
var height = glyf.yMax - glyf.yMin;
|
||||||
var scale = 1;
|
var scale = 1;
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
51
src/graphics/transform.js
Normal file
51
src/graphics/transform.js
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/**
|
||||||
|
* @file transform.js
|
||||||
|
* @author mengke01
|
||||||
|
* @date
|
||||||
|
* @description
|
||||||
|
* 对轮廓进行transform变换
|
||||||
|
*
|
||||||
|
* 参考资料:
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
define(
|
||||||
|
function(require) {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图形仿射矩阵变换
|
||||||
|
*
|
||||||
|
* @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, y, 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return transform;
|
||||||
|
}
|
||||||
|
);
|
||||||
@@ -149,26 +149,29 @@ define(
|
|||||||
val.xMax = reader.readInt16();
|
val.xMax = reader.readInt16();
|
||||||
val.yMax = reader.readInt16();
|
val.yMax = reader.readInt16();
|
||||||
|
|
||||||
// endPtsOfConturs
|
|
||||||
var endPtsOfContours = [];
|
|
||||||
if (numberOfContours >= 0) {
|
|
||||||
for ( var i = 0; i < numberOfContours; i++) {
|
|
||||||
endPtsOfContours.push(reader.readUint16());
|
|
||||||
}
|
|
||||||
val.endPtsOfContours = endPtsOfContours;
|
|
||||||
}
|
|
||||||
|
|
||||||
// instructions
|
|
||||||
var length = reader.readUint16();
|
|
||||||
var instructions = [];
|
|
||||||
for ( var i = 0; i < length; ++i) {
|
|
||||||
instructions.push(reader.readUint8());
|
|
||||||
}
|
|
||||||
|
|
||||||
val.instructions = instructions;
|
|
||||||
|
|
||||||
// 读取简单字形
|
// 读取简单字形
|
||||||
if (numberOfContours >= 0) {
|
if (numberOfContours >= 0) {
|
||||||
|
|
||||||
|
// endPtsOfConturs
|
||||||
|
var endPtsOfContours = [];
|
||||||
|
if (numberOfContours >= 0) {
|
||||||
|
for ( var i = 0; i < numberOfContours; i++) {
|
||||||
|
endPtsOfContours.push(reader.readUint16());
|
||||||
|
}
|
||||||
|
val.endPtsOfContours = endPtsOfContours;
|
||||||
|
}
|
||||||
|
|
||||||
|
// instructions
|
||||||
|
var length = reader.readUint16();
|
||||||
|
if (length) {
|
||||||
|
var instructions = [];
|
||||||
|
for ( var i = 0; i < length; ++i) {
|
||||||
|
instructions.push(reader.readUint8());
|
||||||
|
}
|
||||||
|
val.instructions = instructions;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
readSimpleGlyf.call(
|
readSimpleGlyf.call(
|
||||||
this,
|
this,
|
||||||
reader,
|
reader,
|
||||||
@@ -181,47 +184,77 @@ define(
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val.compound = true;
|
val.compound = true;
|
||||||
val.glyf = [];
|
val.glyfs = [];
|
||||||
|
var flags;
|
||||||
// 读取复杂字形
|
// 读取复杂字形
|
||||||
do {
|
do {
|
||||||
var glyf = {};
|
var glyf = {};
|
||||||
var flags = glyf.flags = reader.readUint16();
|
flags = glyf.flags = reader.readUint16();
|
||||||
val.glyphIndex = reader.readUint16();
|
glyf.glyphIndex = reader.readUint16();
|
||||||
var arg1, arg2, scaleX = 1, scaleY = 1;
|
|
||||||
|
var arg1 = 0, arg2 = 0, scaleX = 16384, scaleY = 16384,
|
||||||
|
scale01 = 0, scale10 = 0;
|
||||||
|
|
||||||
if (componentFlag.ARG_1_AND_2_ARE_WORDS & flags) {
|
if (componentFlag.ARG_1_AND_2_ARE_WORDS & flags) {
|
||||||
if (componentFlag.ARGS_ARE_XY_VALUES & flags) {
|
arg1 = reader.readInt16();
|
||||||
arg1 = reader.readUint16();
|
arg2 = reader.readInt16();
|
||||||
arg2 = reader.readUint16();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
arg1 = reader.readInt16();
|
|
||||||
arg2 = reader.readInt16();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (componentFlag.ARGS_ARE_XY_VALUES & flags) {
|
arg1 = reader.readInt8();
|
||||||
arg1 = reader.readUint8();
|
arg2 = reader.readInt8();
|
||||||
arg2 = reader.readUint8();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
arg1 = reader.readInt8();
|
|
||||||
arg2 = reader.readInt8();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (componentFlag.ROUND_XY_TO_GRID & flags) {
|
if (componentFlag.ROUND_XY_TO_GRID & flags) {
|
||||||
arg1 = Math.round(arg1);
|
arg1 = Math.round(arg1);
|
||||||
arg2 = Math.round(arg2);
|
arg2 = Math.round(arg2);
|
||||||
}
|
}
|
||||||
glyf.x = arg1;
|
|
||||||
glyf.y = arg2;
|
|
||||||
|
|
||||||
val.glyf.push(glyf);
|
if (componentFlag.WE_HAVE_A_SCALE & flags) {
|
||||||
|
scaleX = reader.readInt16();
|
||||||
|
scaleY = scaleX;
|
||||||
|
}
|
||||||
|
else if (componentFlag.WE_HAVE_AN_X_AND_Y_SCALE & flags) {
|
||||||
|
scaleX = reader.readInt16();
|
||||||
|
scaleY = reader.readInt16();
|
||||||
|
}
|
||||||
|
else if (componentFlag.WE_HAVE_A_TWO_BY_TWO & flags) {
|
||||||
|
scaleX = reader.readInt16();
|
||||||
|
scale01 = reader.readInt16();
|
||||||
|
scale10 = reader.readInt16();
|
||||||
|
scaleY = reader.readInt16();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (componentFlag.ARGS_ARE_XY_VALUES & flags) {
|
||||||
|
|
||||||
|
glyf.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 {
|
||||||
|
console.error('not support !ARGS_ARE_XY_VALUES!');
|
||||||
|
}
|
||||||
|
|
||||||
|
val.glyfs.push(glyf);
|
||||||
|
|
||||||
}
|
}
|
||||||
while(componentFlag.MORE_COMPONENTS & flags);
|
while(componentFlag.MORE_COMPONENTS & flags);
|
||||||
}
|
|
||||||
|
if (componentFlag.WE_HAVE_INSTRUCTIONS & flags) {
|
||||||
|
var length = reader.readUint16();
|
||||||
|
var instructions = [];
|
||||||
|
for ( var i = 0; i < length; ++i) {
|
||||||
|
instructions.push(reader.readUint8());
|
||||||
|
}
|
||||||
|
val.instructions = instructions;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,9 +50,29 @@ define(
|
|||||||
*/
|
*/
|
||||||
TTF.prototype.getCodeGlyf = function(c) {
|
TTF.prototype.getCodeGlyf = function(c) {
|
||||||
var glyfIndex = this.getCodeGlyfIndex(c);
|
var glyfIndex = this.getCodeGlyfIndex(c);
|
||||||
return this.ttf.glyf[glyfIndex];
|
return this.getIndexGlyf(glyfIndex);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取字符的glyf信息
|
||||||
|
* @param {number} glyfIndex glyf的索引
|
||||||
|
*
|
||||||
|
* @return {?Object} 返回glyf对象
|
||||||
|
*/
|
||||||
|
TTF.prototype.getIndexGlyf = function(glyfIndex) {
|
||||||
|
var glyfList = this.ttf.glyf;
|
||||||
|
var glyf = glyfList[glyfIndex];
|
||||||
|
// 如果是复合图元, 则把相关的glyf代入
|
||||||
|
if(glyf.compound) {
|
||||||
|
glyf.glyfs.forEach(function(g) {
|
||||||
|
g.glyf = glyfList[g.glyphIndex];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return glyf;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
return TTF;
|
return TTF;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ define(
|
|||||||
|
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
|
ctx.save();
|
||||||
|
|
||||||
if(options.stroke) {
|
if(options.stroke) {
|
||||||
ctx.strokeWidth = options.strokeWidth || 1;
|
ctx.strokeWidth = options.strokeWidth || 1;
|
||||||
ctx.strokeStyle = options.strokeStyle || 'black';
|
ctx.strokeStyle = options.strokeStyle || 'black';
|
||||||
@@ -36,16 +38,43 @@ define(
|
|||||||
ctx.fillStyle = options.fillStyle || 'black';
|
ctx.fillStyle = options.fillStyle || 'black';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var height = glyf.yMax;
|
||||||
|
ctx.translate(options.x || 0, height + (options.y || 0));
|
||||||
|
ctx.scale(options.scale || 1, -(options.scale || 1));
|
||||||
|
|
||||||
// 对轮廓进行反向,以及坐标系调整,取整
|
|
||||||
glyf = glyfAdjust(glyf, options.scale, options.x, options.y);
|
|
||||||
|
|
||||||
var contours = glyf.contours;
|
|
||||||
|
|
||||||
// 处理glyf轮廓
|
// 处理glyf轮廓
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
for ( var i = 0, l = contours.length; i < l; i++) {
|
|
||||||
drawContour(ctx, contours[i]);
|
if (!glyf.compound) {
|
||||||
|
|
||||||
|
var contours = glyf.contours;
|
||||||
|
for ( var i = 0, l = contours.length; i < l; i++) {
|
||||||
|
drawContour(ctx, contours[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 复合图元绘制
|
||||||
|
else {
|
||||||
|
var glyfs = glyf.glyfs;
|
||||||
|
glyfs.forEach(function(g) {
|
||||||
|
|
||||||
|
ctx.save();
|
||||||
|
var transform = g.transform;
|
||||||
|
ctx.transform (
|
||||||
|
transform.a,
|
||||||
|
transform.b,
|
||||||
|
transform.c,
|
||||||
|
transform.d,
|
||||||
|
transform.e,
|
||||||
|
transform.f
|
||||||
|
);
|
||||||
|
|
||||||
|
var contours = g.glyf.contours;
|
||||||
|
for ( var i = 0, l = contours.length; i < l; i++) {
|
||||||
|
drawContour(ctx, contours[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.restore();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if(false !== options.stroke) {
|
if(false !== options.stroke) {
|
||||||
@@ -55,6 +84,7 @@ define(
|
|||||||
if (false !== options.fill) {
|
if (false !== options.fill) {
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
}
|
}
|
||||||
|
ctx.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,8 @@
|
|||||||
define(
|
define(
|
||||||
function(require) {
|
function(require) {
|
||||||
var contour2svg = require('./contour2svg');
|
var contour2svg = require('./contour2svg');
|
||||||
var glyfAdjust = require('ttf/util/glyfAdjust');
|
var pathAdjust = require('graphics/pathAdjust');
|
||||||
|
var matrixTransform = require('graphics/transform');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* glyf转换svg
|
* glyf转换svg
|
||||||
@@ -27,15 +28,39 @@ define(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var pathArray = [];
|
var pathArray = [];
|
||||||
|
|
||||||
|
|
||||||
// 对轮廓进行反向,以及坐标系调整,取整
|
|
||||||
glyf = glyfAdjust(glyf, options.scale, options.x, options.y);
|
|
||||||
|
|
||||||
var contours = glyf.contours;
|
var contours = glyf.contours;
|
||||||
|
var height = glyf.yMax;
|
||||||
for ( var i = 0, l = contours.length; i < l; i++) {
|
var x = options.x || 0;
|
||||||
pathArray.push(contour2svg(contours[i]));
|
var y = height + (options.y || 0);
|
||||||
|
var scale = options.scale || 1;
|
||||||
|
|
||||||
|
|
||||||
|
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]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var glyfs = glyf.glyfs;
|
||||||
|
glyfs.forEach(function(g) {
|
||||||
|
var contours = g.glyf.contours;
|
||||||
|
var transform = g.transform;
|
||||||
|
for ( var i = 0, l = contours.length; i < l; i++) {
|
||||||
|
matrixTransform(contours[i],
|
||||||
|
transform.a,
|
||||||
|
transform.b,
|
||||||
|
transform.c,
|
||||||
|
transform.d,
|
||||||
|
transform.e,
|
||||||
|
transform.f
|
||||||
|
);
|
||||||
|
pathAdjust(contours[i], 1, -1);
|
||||||
|
pathAdjust(contours[i], scale, scale, x, y);
|
||||||
|
pathArray.push(contour2svg(contours[i]));
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return pathArray.join(' ');
|
return pathArray.join(' ');
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file glyfAdjust.js
|
|
||||||
* @author mengke01
|
|
||||||
* @date
|
|
||||||
* @description
|
|
||||||
* 将glyf坐标系平移到原点
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
define(
|
|
||||||
function(require) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对glyf坐标进行调整
|
|
||||||
*
|
|
||||||
* @param {Object} glyf glyf结构
|
|
||||||
* @param {number} scale 缩放比例
|
|
||||||
* @param {number} offsetX x偏移
|
|
||||||
* @param {number} offsetY y偏移
|
|
||||||
* @return {number} glyf结构
|
|
||||||
*/
|
|
||||||
function glyfAdjust(glyf, scale, offsetX, offsetY) {
|
|
||||||
|
|
||||||
// 对轮廓进行反向,以及坐标系调整,取整
|
|
||||||
var middleYx2 = glyf.yMax + glyf.yMin;
|
|
||||||
var scale = scale || 1;
|
|
||||||
var x = offsetX || 0;
|
|
||||||
var y = offsetY || 0;
|
|
||||||
|
|
||||||
glyf.contours.forEach(function (path) {
|
|
||||||
path.forEach(function(p) {
|
|
||||||
p.x = x + scale * (p.x);
|
|
||||||
p.y = y + scale * (middleYx2 - p.y);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
glyf.xMin = x + glyf.xMin * scale;
|
|
||||||
glyf.yMin = y + glyf.yMin * scale;
|
|
||||||
glyf.xMax = x + glyf.xMax * scale;
|
|
||||||
glyf.yMax = y + glyf.yMax * scale;
|
|
||||||
|
|
||||||
return glyf;
|
|
||||||
}
|
|
||||||
|
|
||||||
return glyfAdjust;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
Reference in New Issue
Block a user