增加svg导入 自动调整大小

This commit is contained in:
kekee000 2015-01-05 15:02:33 +08:00
parent e70014f381
commit 41f1322992
7 changed files with 169 additions and 104 deletions

View File

@ -32,7 +32,8 @@ define(
program.loading.hide();
if (program.ttfManager.get()) {
program.ttfManager.merge(imported, {
scale: true
scale: true,
adjustGlyf: imported.from === 'svg' ? true : false
});
}
else {

View File

@ -40,6 +40,11 @@ define(
url: 'http://vs-static.baidu.com/m-health/new-composite/20141223/asset/common/css/font/baiduHealth.woff',
from: '百度健康图标'
},
{
name: 'fonteditor.woff',
url: 'http://vs-static.baidu.com/m-health/med-detail/201412301413/asset/common/css/fonts/fonteditor.woff',
from: '百度健康医药馆图标'
},
{
name: 'i-edu.woff',
url: 'http://vs-static.baidu.com/edu/m/asset/common/css/font/i-edu.woff',

View File

@ -47,7 +47,10 @@ define(
type: ext,
success: function (imported) {
if (imported.glyf.length) {
program.ttfManager.merge(imported, {scale: true});
program.ttfManager.merge(imported, {
scale: true,
adjustGlyf: imported.from === 'svg' ? true : false
});
}
}
});

View File

@ -162,6 +162,7 @@ define(
* @param {Object} imported ttfObject
* @param {Object} options 参数选项
* @param {boolean} options.scale 是否自动缩放
* @param {boolean} options.adjustGlyf 是否调整字形以适应边界
*
* @return {this}
*/

View File

@ -13,6 +13,7 @@ define(
var svg2contours = require('./util/svg2contours');
var computeBoundingBox = require('graphics/computeBoundingBox');
var error = require('./error');
var glyfAdjust = require('./util/glyfAdjust');
/**
* 加载xml字符串
@ -51,6 +52,39 @@ define(
};
}
/**
* 根据边界获取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 = unitsPerEm << 1;
}
return 1024;
}
/**
* 对ttfObject进行处理去除小数
@ -60,58 +94,41 @@ define(
*/
function resolve(ttf) {
var scale = 1;
// 对于小尺寸svg进行合理的缩放
if (ttf.head.unitsPerEm && ttf.head.unitsPerEm < 256) {
scale = 1024 / ttf.head.unitsPerEm;
// 如果是svg格式字体则去小数
if (ttf.from === 'svgfont' && ttf.head.unitsPerEm > 128) {
ttf.glyf.forEach(function (g) {
glyfAdjust(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(null, 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) {
glyfAdjust(g, scale, scale);
});
ttf.head.unitsPerEm = 1024;
}
ttf.glyf.forEach(function (glyf) {
if (glyf.contours && glyf.contours.length) {
var pointIterator = function (p) {
p.x = Math.round(p.x * scale);
p.y = Math.round(p.y * scale);
};
var contourIterator = function (contour) {
contour.forEach(pointIterator);
};
glyf.contours.forEach(contourIterator);
var bound = computeBoundingBox.computePathBox.apply(null, glyf.contours);
glyf.xMin = bound.x;
glyf.xMax = bound.x + bound.width;
glyf.yMin = bound.y;
glyf.yMax = bound.y + bound.height;
if (glyf.leftSideBearing) {
glyf.leftSideBearing = Math.round(glyf.leftSideBearing * scale);
}
else {
glyf.leftSideBearing = glyf.xMin;
}
if (glyf.advanceWidth) {
glyf.advanceWidth = Math.round(glyf.advanceWidth * scale);
}
else {
glyf.advanceWidth = glyf.xMax + Math.abs(glyf.xMin);
}
}
});
if (undefined !== ttf.head.xMin && undefined !== ttf.head.yMax) {
ttf.head.xMin = Math.round(ttf.head.xMin * scale);
ttf.head.xMax = Math.round(ttf.head.xMax * scale);
ttf.head.yMin = Math.round(ttf.head.yMin * scale);
ttf.head.yMax = Math.round(ttf.head.yMax * scale);
}
ttf.head.unitsPerEm = ttf.head.unitsPerEm ? Math.round(ttf.head.unitsPerEm) : 1024;
return ttf;
}
@ -132,10 +149,11 @@ define(
ttf.metadata = string.decodeHTML(metaNode.textContent.trim());
}
// 解析font
// 解析font如果有font节点说明是svg格式字体文件
if (fontNode) {
ttf.id = fontNode.getAttribute('id') || '';
ttf.hhea.advanceWidthMax = +(fontNode.getAttribute('horiz-adv-x') || 0);
ttf.from = 'svgfont';
}
if (fontFaceNode) {
@ -174,15 +192,6 @@ define(
}
}
// 如果没有定义unitsPerEm可以用viewBox代替
var svgNode = xmlDoc.getElementsByTagName('svg')[0];
if (!ttf.head.unitsPerEm && svgNode.getAttribute('viewBox')) {
var bound = svgNode.getAttribute('viewBox').split(' ');
if (bound.length === 4) {
ttf.head.unitsPerEm = +bound[2];
}
}
return ttf;
}

View File

@ -18,6 +18,54 @@ define(
var computeBoundingBox = require('graphics/computeBoundingBox');
var glyfAdjust = require('./util/glyfAdjust');
/**
* 缩放到EM框
*
* @param {Array} glyfList glyf列表
* @param {number} ascent 上升
* @param {number} descent 下降
* @param {number} ajdustToEmPadding 顶部和底部留白
* @return {Array} glyfList
*/
function adjustToEmBox(glyfList, ascent, descent, ajdustToEmPadding) {
glyfList.forEach(function (g) {
if (g.contours && g.contours.length) {
var rightSideBearing = g.advanceWidth - g.xMax;
var bound = computeBoundingBox.computePath.apply(null, g.contours);
var scale = (ascent - descent - ajdustToEmPadding) / bound.height;
var center = (ascent + descent) / 2;
var yOffset = center - (bound.y + bound.height / 2) * scale;
g.contours.forEach(function (contour) {
if (scale !== 1) {
pathAdjust(contour, scale, scale);
}
pathAdjust(contour, 1, 1, 0, yOffset);
pathCeil(contour);
});
var box = computeBoundingBox.computePathBox.apply(null, 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;
}
/**
* 合并两个ttfObject此处仅合并简单字形
*
@ -25,18 +73,13 @@ define(
* @param {Object} imported ttfObject
* @param {Object} options 参数选项
* @param {boolean} options.scale 是否自动缩放
* @param {boolean} options.adjustGlyf 是否调整字形以适应边界
*
* @return {Object} 合并后的ttfObject
*/
function merge(ttf, imported, options) {
options = options || {};
var scale = 1;
// 调整glyf对导入的轮廓进行缩放处理
if (options.scale && imported.head.unitsPerEm && imported.head.unitsPerEm !== ttf.head.unitsPerEm) {
scale = ttf.head.unitsPerEm / imported.head.unitsPerEm;
}
var list = imported.glyf.filter(function (g, index) {
// 简单轮廓
return g.contours && g.contours.length
@ -44,14 +87,37 @@ define(
&& g.name !== '.notdef' && g.name !== '.null' && g.name !== 'nonmarkingreturn';
});
list.forEach(function (g) {
glyfAdjust(g, scale, scale);
ttf.glyf.push(g);
});
// 调整字形以适应边界
if (options.adjustGlyf) {
var ascent = ttf.hhea.ascent;
var descent = ttf.hhea.descent;
var ajdustToEmPadding = 0;
adjustToEmBox(list, ascent, descent, ajdustToEmPadding);
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) {
glyfAdjust(g, scale, scale);
ttf.glyf.push(g);
});
}
return list;
}
/**
* ttf读取函数
*
@ -342,7 +408,6 @@ define(
// 基线高度
if (undefined !== setting.verticalAlign) {
changed = true;
var verticalAlign = setting.verticalAlign || 0;
@ -404,39 +469,11 @@ define(
else if (setting.ajdustToEmBox) {
changed = true;
var dencent = this.ttf.hhea.descent;
var unitsPerEm = this.ttf.head.unitsPerEm;
var ascent = this.ttf.hhea.ascent;
var descent = this.ttf.hhea.descent;
var ajdustToEmPadding = 2 * (setting.ajdustToEmPadding || 0);
glyfList.forEach(function (g) {
if (g.contours && g.contours.length) {
var rightSideBearing = g.advanceWidth - g.xMax;
var bound = computeBoundingBox.computePath.apply(null, g.contours);
var scale = (unitsPerEm - ajdustToEmPadding) / bound.height;
if (scale !== 1) {
var yOffset = (unitsPerEm / 2 + dencent) - (bound.y + bound.height / 2) * scale;
g.contours.forEach(function (contour) {
pathAdjust(contour, scale, scale);
pathAdjust(contour, 1, 1, 0, yOffset);
pathCeil(contour);
});
var box = computeBoundingBox.computePathBox.apply(null, 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;
}
}
});
adjustToEmBox(glyfList, ascent, descent, ajdustToEmPadding);
}
return changed ? glyfList : [];

View File

@ -14,6 +14,7 @@ define(
var pathCeil = require('graphics/pathCeil');
var computeBoundingBox = require('graphics/computeBoundingBox');
/* eslint-disable max-params */
/**
* 简单字形的缩放和平移调整
*
@ -22,9 +23,11 @@ define(
* @param {number} scaleY y缩放比例
* @param {number} offsetX x偏移
* @param {number} offsetY y偏移
* @param {boolan} ceil 是否对字形设置取整默认取整
*
* @return {Object} 调整后的glyf对象
*/
function glyfAdjust(g, scaleX, scaleY, offsetX, offsetY) {
function glyfAdjust(g, scaleX, scaleY, offsetX, offsetY, ceil) {
scaleX = scaleX || 1;
scaleY = scaleY || 1;
@ -35,7 +38,6 @@ define(
if (scaleX !== 1 || scaleY !== 1) {
g.contours.forEach(function (contour) {
pathAdjust(contour, scaleX, scaleY);
pathCeil(contour);
});
}
@ -44,6 +46,12 @@ define(
pathAdjust(contour, 1, 1, offsetX, offsetY);
});
}
if (false !== ceil) {
g.contours.forEach(function (contour) {
pathCeil(contour);
});
}
}
// 重新计算xminxmaxyminymax
@ -94,6 +102,7 @@ define(
return g;
}
/* eslint-enable max-params */
return glyfAdjust;
}