add compound glyf

This commit is contained in:
mkwiser
2014-09-25 23:26:55 +08:00
parent 9228694de9
commit d0e96dc855
11 changed files with 228 additions and 120 deletions

View File

@@ -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);

View File

@@ -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
View 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;
}
);

View File

@@ -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;
} }

View File

@@ -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;
} }
); );

View File

@@ -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();
} }

View File

@@ -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(' ');

View File

@@ -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;
}
);