diff --git a/demo/js/glyfcanvas.js b/demo/js/glyfcanvas.js index d814914..89c1894 100644 --- a/demo/js/glyfcanvas.js +++ b/demo/js/glyfcanvas.js @@ -15,6 +15,7 @@ define( var ajaxBinaryFile = require('common/ajaxBinaryFile'); var setFontface = require('./setFontface'); var glyf2canvas = require('ttf/util/glyf2canvas'); + var lang = require('common/lang'); var ttf = null; @@ -44,15 +45,8 @@ define( } function showGlyf(charcode) { - var glyfData = ttf.getCodeGlyf(charcode); - - var glyf = { - xMin: glyfData.xMin, - xMax: glyfData.xMax, - yMin: glyfData.yMin, - yMax: glyfData.yMax, - contours: glyfData.contours - }; + + var glyf = lang.clone(ttf.getCodeGlyf(charcode)); var canvas = $('#glyf-canvas').get(0); diff --git a/demo/js/glyfsvg.js b/demo/js/glyfsvg.js index 2384281..116ba97 100644 --- a/demo/js/glyfsvg.js +++ b/demo/js/glyfsvg.js @@ -15,6 +15,9 @@ define( var ajaxBinaryFile = require('common/ajaxBinaryFile'); var glyf2svg = require('ttf/util/glyf2svg'); var setFontface = require('./setFontface'); + var lang = require('common/lang'); + + var ttf = null; // 设置字体 @@ -26,7 +29,7 @@ define( // 查看ttf glyf function showTTFGlyf(ttfData) { - console.log(ttfData); + ttf = new TTF(ttfData); var codes = ttf.codes(); @@ -53,11 +56,10 @@ define( + '' + ''; var svg = $(tpl); - var glyf = ttf.getCodeGlyf(charcode); - var lang = require('common/lang'); - + var glyf = lang.clone(ttf.getCodeGlyf(charcode)); + // 调整大小 - var width = glyf.xMax - glyf.xMin; + var width = glyf.xMax; var height = glyf.yMax - glyf.yMin; var scale = 1; diff --git a/font/baiduHealth.fcp b/font/baiduHealth.fcp index 65f2c70..e6a3d94 100644 Binary files a/font/baiduHealth.fcp and b/font/baiduHealth.fcp differ diff --git a/font/baiduHealth.ttf b/font/baiduHealth.ttf index 42e0278..0df71c6 100644 Binary files a/font/baiduHealth.ttf and b/font/baiduHealth.ttf differ diff --git a/font/baiduHealth.woff b/font/baiduHealth.woff index 05ed7b5..b5e98f4 100644 Binary files a/font/baiduHealth.woff and b/font/baiduHealth.woff differ diff --git a/src/graphics/transform.js b/src/graphics/transform.js new file mode 100644 index 0000000..c67c0f5 --- /dev/null +++ b/src/graphics/transform.js @@ -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.} 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.} 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; + } +); diff --git a/src/ttf/table/ttfglyf.js b/src/ttf/table/ttfglyf.js index 4d06927..a901f54 100644 --- a/src/ttf/table/ttfglyf.js +++ b/src/ttf/table/ttfglyf.js @@ -149,26 +149,29 @@ define( val.xMax = 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) { + + // 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( this, reader, @@ -181,47 +184,77 @@ define( } else { val.compound = true; - val.glyf = []; + val.glyfs = []; + var flags; // 读取复杂字形 do { var glyf = {}; - var flags = glyf.flags = reader.readUint16(); - val.glyphIndex = reader.readUint16(); - var arg1, arg2, scaleX = 1, scaleY = 1; + flags = glyf.flags = reader.readUint16(); + glyf.glyphIndex = reader.readUint16(); + + var arg1 = 0, arg2 = 0, scaleX = 16384, scaleY = 16384, + scale01 = 0, scale10 = 0; + if (componentFlag.ARG_1_AND_2_ARE_WORDS & flags) { - if (componentFlag.ARGS_ARE_XY_VALUES & flags) { - arg1 = reader.readUint16(); - arg2 = reader.readUint16(); - } - else { - arg1 = reader.readInt16(); - arg2 = reader.readInt16(); - } + arg1 = reader.readInt16(); + arg2 = reader.readInt16(); } else { - if (componentFlag.ARGS_ARE_XY_VALUES & flags) { - arg1 = reader.readUint8(); - arg2 = reader.readUint8(); - } - else { - arg1 = reader.readInt8(); - arg2 = reader.readInt8(); - } + arg1 = reader.readInt8(); + arg2 = reader.readInt8(); } if (componentFlag.ROUND_XY_TO_GRID & flags) { arg1 = Math.round(arg1); 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); - } + + 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; } diff --git a/src/ttf/ttf.js b/src/ttf/ttf.js index 2b99e44..5b8818f 100644 --- a/src/ttf/ttf.js +++ b/src/ttf/ttf.js @@ -50,9 +50,29 @@ define( */ TTF.prototype.getCodeGlyf = function(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; } ); diff --git a/src/ttf/util/glyf2canvas.js b/src/ttf/util/glyf2canvas.js index 763dcf4..54395ea 100644 --- a/src/ttf/util/glyf2canvas.js +++ b/src/ttf/util/glyf2canvas.js @@ -28,6 +28,8 @@ define( options = options || {}; + ctx.save(); + if(options.stroke) { ctx.strokeWidth = options.strokeWidth || 1; ctx.strokeStyle = options.strokeStyle || 'black'; @@ -36,16 +38,43 @@ define( 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轮廓 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) { @@ -55,6 +84,7 @@ define( if (false !== options.fill) { ctx.fill(); } + ctx.restore(); } diff --git a/src/ttf/util/glyf2svg.js b/src/ttf/util/glyf2svg.js index 25bf60c..38c6690 100644 --- a/src/ttf/util/glyf2svg.js +++ b/src/ttf/util/glyf2svg.js @@ -14,7 +14,8 @@ define( function(require) { var contour2svg = require('./contour2svg'); - var glyfAdjust = require('ttf/util/glyfAdjust'); + var pathAdjust = require('graphics/pathAdjust'); + var matrixTransform = require('graphics/transform'); /** * glyf转换svg @@ -27,15 +28,39 @@ define( return null; } var pathArray = []; - - - // 对轮廓进行反向,以及坐标系调整,取整 - glyf = glyfAdjust(glyf, options.scale, options.x, options.y); - var contours = glyf.contours; - - for ( var i = 0, l = contours.length; i < l; i++) { - pathArray.push(contour2svg(contours[i])); + var height = glyf.yMax; + var x = options.x || 0; + 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(' '); diff --git a/src/ttf/util/glyfAdjust.js b/src/ttf/util/glyfAdjust.js deleted file mode 100644 index 3f4f708..0000000 --- a/src/ttf/util/glyfAdjust.js +++ /dev/null @@ -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; - } -);