增加glyf查看器
This commit is contained in:
parent
2c81e350fb
commit
9973d33c63
65
demo/css/glyf.css
Normal file
65
demo/css/glyf.css
Normal file
@ -0,0 +1,65 @@
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
ul {
|
||||
list-style: none;
|
||||
}
|
||||
a {
|
||||
color: #03C;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
body {
|
||||
font-size: 13px;
|
||||
}
|
||||
.upload-file {
|
||||
margin: 20px;
|
||||
}
|
||||
.i-font {
|
||||
font-family: 'truetype';
|
||||
display: inline-block;
|
||||
margin-right: 6px;
|
||||
color: green;
|
||||
}
|
||||
.font-list {
|
||||
height: 200px;
|
||||
overflow: auto;
|
||||
}
|
||||
.font-list li {
|
||||
width: 70px;
|
||||
float: left;
|
||||
padding: 10px;
|
||||
border: 1px solid #EEE;
|
||||
list-style: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
.font-list li:hover {
|
||||
background: #E0E0E0;
|
||||
}
|
||||
.font-list li.selected {
|
||||
background: #ECECEC;
|
||||
}
|
||||
.svg-view {
|
||||
width: 500px;
|
||||
height: 500px;
|
||||
background: #F0F0F0;
|
||||
}
|
||||
.glyf {
|
||||
width: 100%;
|
||||
}
|
||||
.glyf .path {
|
||||
fill: green;
|
||||
stroke: none;
|
||||
stroke-width: 10px;
|
||||
}
|
||||
.boundary {
|
||||
fill: none;
|
||||
stroke-width: 1px;
|
||||
stroke: black;
|
||||
}
|
60
demo/css/glyf.less
Normal file
60
demo/css/glyf.less
Normal file
@ -0,0 +1,60 @@
|
||||
|
||||
@import './reset';
|
||||
|
||||
body {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.upload-file {
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.i-font {
|
||||
font-family: 'truetype';
|
||||
display: inline-block;
|
||||
margin-right: 6px;
|
||||
color: green;
|
||||
}
|
||||
|
||||
|
||||
.font-list {
|
||||
height: 200px;
|
||||
overflow: auto;
|
||||
|
||||
li {
|
||||
width: 70px;
|
||||
float: left;
|
||||
padding: 10px;
|
||||
border: 1px solid #EEE;
|
||||
list-style: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
li:hover {
|
||||
background: #E0E0E0;
|
||||
}
|
||||
li.selected {
|
||||
background: #ECECEC;
|
||||
}
|
||||
}
|
||||
|
||||
.svg-view {
|
||||
width: 500px;
|
||||
height: 500px;
|
||||
background: #F0F0F0;
|
||||
}
|
||||
|
||||
.glyf {
|
||||
width: 100%;
|
||||
.path {
|
||||
fill: green;
|
||||
stroke: none;
|
||||
stroke-width: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.boundary {
|
||||
fill: none;
|
||||
stroke-width: 1px;
|
||||
stroke: black;
|
||||
}
|
18
demo/css/reset.less
Normal file
18
demo/css/reset.less
Normal file
@ -0,0 +1,18 @@
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
ul {
|
||||
list-style: none;
|
||||
}
|
||||
a {
|
||||
color: #03C;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
35
demo/glyf.html
Normal file
35
demo/glyf.html
Normal file
@ -0,0 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>glyf查看</title>
|
||||
<script src="http://s1.bdstatic.com/r/www/cache/ecom/esl/1-8-2/esl.js"></script>
|
||||
<script src="http://libs.baidu.com/jquery/1.9.0/jquery.min.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="./css/glyf.css">
|
||||
<style id="font-face"></style>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
require.config({
|
||||
baseUrl: './js',
|
||||
paths: {
|
||||
editor: '../../src',
|
||||
}
|
||||
});
|
||||
define('jquery', $);
|
||||
</script>
|
||||
|
||||
<form>
|
||||
<input id="upload-file" type="file" class="upload-file">
|
||||
</form>
|
||||
|
||||
<ul id="font-list" class="font-list"></ul>
|
||||
|
||||
<div id="svg-view" class="svg-view"></div>
|
||||
|
||||
<script>
|
||||
require(['glyf']);
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
127
demo/js/glyf.js
Normal file
127
demo/js/glyf.js
Normal file
@ -0,0 +1,127 @@
|
||||
/**
|
||||
* @file glyf.js
|
||||
* @author mengke01
|
||||
* @date
|
||||
* @description
|
||||
* glyf 查看
|
||||
*/
|
||||
|
||||
define(
|
||||
function(require) {
|
||||
|
||||
var ttfreader = require('editor/ttf/ttfreader');
|
||||
var TTF = require('editor/ttf/ttf');
|
||||
var ttf2base64 = require('editor/ttf/ttf2base64');
|
||||
var ajaxBinaryFile = require('editor/common/ajaxBinaryFile');
|
||||
var glyf2svg = require('editor/ttf/glyf2svg');
|
||||
var setFontface = require('./setFontface');
|
||||
var ttf = null;
|
||||
|
||||
// 设置字体
|
||||
function setFont(arrayBuffer) {
|
||||
var base64 = ttf2base64(arrayBuffer);
|
||||
setFontface('truetype', base64, 'font-face');
|
||||
}
|
||||
|
||||
|
||||
// 查看ttf glyf
|
||||
function showTTFGlyf(ttfData) {
|
||||
ttf = new TTF(ttfData);
|
||||
var chars = ttf.chars();
|
||||
|
||||
var str = '';
|
||||
|
||||
// 获取unicode字符
|
||||
chars.forEach(function(item) {
|
||||
str += '<li data-code="'+ item +'">'
|
||||
+ '<span class="i-font">'+ String.fromCharCode(item) +'</span>'
|
||||
+ (item > 255 ? '\\u' + Number(item).toString(16) : item)
|
||||
+'</li>';
|
||||
});
|
||||
|
||||
$('#font-list').html(str);
|
||||
|
||||
$('#font-list li:nth-child(4)').click();
|
||||
}
|
||||
|
||||
function showGlyf(charcode) {
|
||||
var tpl = ''
|
||||
+ '<svg class="glyf" viewBox="0 0 1200 2000">'
|
||||
+ ' <g transform="translate(1000, 0) scale(-1, 1) rotate(180, 500, 500)">'
|
||||
+ '<polyline class="boundary" points="" />'
|
||||
+ '<path class="path" d="M 0,0" />'
|
||||
+ '</g>'
|
||||
+ '</svg>';
|
||||
var svg = $(tpl);
|
||||
var glyf = ttf.getCharGlyf(charcode);
|
||||
var path = glyf2svg(glyf);
|
||||
if (path) {
|
||||
var scale = 1000 / ttf.ttf.head.unitsPerEm;
|
||||
var boundary = ''
|
||||
+ glyf.xMin + ',' + glyf.yMin + ' '
|
||||
+ glyf.xMin + ',' + glyf.yMax + ' '
|
||||
+ glyf.xMax + ',' + glyf.yMax + ' '
|
||||
+ glyf.xMax + ',' + glyf.yMin + ' '
|
||||
+ glyf.xMin + ',' + glyf.yMin + ' ';
|
||||
|
||||
svg.find(".boundary").attr('points', boundary).attr('transform', 'scale(' + scale + ',' + scale + ')');
|
||||
svg.find(".path").attr('d', path).attr('transform', 'scale(' + scale + ',' + scale + ')');
|
||||
}
|
||||
|
||||
$('#svg-view').html(svg);
|
||||
}
|
||||
|
||||
|
||||
function onUpFileChange(e) {
|
||||
var file = e.target.files[0];
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
var binaryData = e.target.result;
|
||||
setFont(binaryData);
|
||||
|
||||
var ttfData = new ttfreader().read(binaryData);
|
||||
showTTFGlyf(ttfData);
|
||||
}
|
||||
|
||||
reader.onerror = function(e) {
|
||||
console.error(e);
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
}
|
||||
|
||||
var entry = {
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
init: function() {
|
||||
var upFile = document.getElementById('upload-file');
|
||||
upFile.addEventListener('change', onUpFileChange);
|
||||
|
||||
ajaxBinaryFile({
|
||||
url: '../font/baiduHealth.ttf',
|
||||
onSuccess: function(binaryData) {
|
||||
setFont(binaryData);
|
||||
|
||||
var ttfData = new ttfreader().read(binaryData);
|
||||
showTTFGlyf(ttfData);
|
||||
},
|
||||
onError: function() {
|
||||
console.error('error read file');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$('#font-list').delegate('li', 'click', function(e) {
|
||||
$('#font-list li').removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
showGlyf(+$(this).attr('data-code'));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
entry.init();
|
||||
|
||||
return entry;
|
||||
}
|
||||
);
|
31
demo/js/setFontface.js
Normal file
31
demo/js/setFontface.js
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* @file setFontface.js
|
||||
* @author mengke01
|
||||
* @date
|
||||
* @description
|
||||
* 设置fontface
|
||||
*/
|
||||
|
||||
|
||||
define(
|
||||
function(require) {
|
||||
|
||||
/**
|
||||
* 设置fontface的ttf字体
|
||||
* @param {name} name 字体名
|
||||
* @param {string} ttfBase64 base64字体
|
||||
* @param {string} styleId domId
|
||||
*/
|
||||
function setFontface(name, ttfBase64, styleId) {
|
||||
var str = ''
|
||||
+ '@font-face {'
|
||||
+ 'font-family:\'' + name + '\';'
|
||||
+ 'src:url(data:font/ttf;charset=utf-8;base64,'
|
||||
+ ttfBase64
|
||||
+ ') format(\'truetype\');'
|
||||
+ '}';
|
||||
document.getElementById(styleId).innerHTML = str;
|
||||
}
|
||||
return setFontface;
|
||||
}
|
||||
);
|
BIN
font/arial.ttf
Normal file
BIN
font/arial.ttf
Normal file
Binary file not shown.
158
src/ttf/glyf2svg.js
Normal file
158
src/ttf/glyf2svg.js
Normal file
@ -0,0 +1,158 @@
|
||||
/**
|
||||
* @file glyf2svg.js
|
||||
* @author mengke01
|
||||
* @date
|
||||
* @description
|
||||
* glyf转换svg
|
||||
*
|
||||
* thanks to:
|
||||
* ynakajima/ttf.js
|
||||
* https://github.com/ynakajima/ttf.js
|
||||
*/
|
||||
|
||||
|
||||
define(
|
||||
function(require) {
|
||||
|
||||
/**
|
||||
* glyf转换svg
|
||||
*
|
||||
* @param {Object} glyf 解析后的glyf结构
|
||||
* @return {string} svg文本
|
||||
*/
|
||||
function glyf2svg(glyf) {
|
||||
|
||||
var pathArray = [];
|
||||
var startPts = 0; // 起始点
|
||||
var currentPts = 0; // 结束点
|
||||
|
||||
if(!glyf) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 处理glyf轮廓
|
||||
for ( var i = 0, l = glyf.endPtsOfContours.length; i < l; i++) {
|
||||
try {
|
||||
// 处理glyf坐标
|
||||
for ( var endPts = glyf.endPtsOfContours[i]; currentPts < endPts + 1; currentPts++) {
|
||||
|
||||
var path = "";
|
||||
var currentPoint = glyf.coordinates[currentPts];
|
||||
var prevPoint = (currentPts === startPts)
|
||||
? glyf.coordinates[endPts]
|
||||
: glyf.coordinates[currentPts - 1];
|
||||
var nextPoint = (currentPts === endPts)
|
||||
? glyf.coordinates[startPts]
|
||||
: glyf.coordinates[currentPts + 1];
|
||||
|
||||
if (currentPoint == undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 处理起始点
|
||||
if (currentPts === startPts) {
|
||||
if (currentPoint.isOnCurve) {
|
||||
path += "M"
|
||||
+ currentPoint.x
|
||||
+ ","
|
||||
+ currentPoint.y
|
||||
+ " ";
|
||||
}
|
||||
// 起始点不在曲线上
|
||||
else {
|
||||
|
||||
var midPoint = {
|
||||
x : (prevPoint.x + currentPoint.x) / 2,
|
||||
y : (prevPoint.y + currentPoint.y) / 2
|
||||
};
|
||||
|
||||
path += "M"
|
||||
+ midPoint.x
|
||||
+ ","
|
||||
+ midPoint.y
|
||||
+ " Q"
|
||||
+ currentPoint.x
|
||||
+ ","
|
||||
+ currentPoint.y
|
||||
+ " ";
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
// 直线
|
||||
if (
|
||||
currentPoint != undefined
|
||||
&& currentPoint.isOnCurve
|
||||
&& prevPoint != undefined
|
||||
&& prevPoint.isOnCurve
|
||||
) {
|
||||
path += " L";
|
||||
}
|
||||
// 当前点不在曲线上
|
||||
else if (
|
||||
!currentPoint.isOnCurve
|
||||
&& prevPoint != undefined
|
||||
&& !prevPoint.isOnCurve
|
||||
) {
|
||||
|
||||
var midPoint = {
|
||||
x : (prevPoint.x + currentPoint.x) / 2,
|
||||
y : (prevPoint.y + currentPoint.y) / 2
|
||||
};
|
||||
path += midPoint.x
|
||||
+ ","
|
||||
+ midPoint.y
|
||||
+ " ";
|
||||
}
|
||||
// 当前坐标不在曲线上
|
||||
else if (!currentPoint.isOnCurve) {
|
||||
path += " Q";
|
||||
}
|
||||
|
||||
// 当前坐标
|
||||
path += currentPoint.x + "," + currentPoint.y + " ";
|
||||
}
|
||||
pathArray.push(path);
|
||||
}
|
||||
|
||||
// 当前点不在曲线上
|
||||
if (
|
||||
!currentPoint.isOnCurve
|
||||
&& glyf.coordinates[startPts] != undefined
|
||||
) {
|
||||
|
||||
// 轮廓起始点在曲线上
|
||||
if (glyf.coordinates[startPts].isOnCurve) {
|
||||
pathArray.push(
|
||||
glyf.coordinates[startPts].x
|
||||
+ ","
|
||||
+ glyf.coordinates[startPts].y
|
||||
+ " "
|
||||
);
|
||||
}
|
||||
else {
|
||||
var midPoint = {
|
||||
x : (currentPoint.x + glyf.coordinates[startPts].x) / 2,
|
||||
y : (currentPoint.y + glyf.coordinates[startPts].y) / 2
|
||||
};
|
||||
pathArray.push(midPoint.x + "," + midPoint.y + " ");
|
||||
}
|
||||
}
|
||||
|
||||
// 结束轮廓
|
||||
pathArray.push(" Z ");
|
||||
|
||||
// 处理下一个轮廓
|
||||
startPts = glyf.endPtsOfContours[i] + 1;
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return pathArray.join(" ");
|
||||
}
|
||||
|
||||
|
||||
|
||||
return glyf2svg;
|
||||
}
|
||||
);
|
@ -4,13 +4,17 @@
|
||||
* @date
|
||||
* @description
|
||||
* ttf读取器
|
||||
*
|
||||
* thanks to:
|
||||
* ynakajima/ttf.js
|
||||
* https://github.com/ynakajima/ttf.js
|
||||
*/
|
||||
|
||||
define(
|
||||
function(require) {
|
||||
|
||||
var extend = require('common/lang').extend;
|
||||
var curry = require('common/lang').curry;
|
||||
var extend = require('../common/lang').extend;
|
||||
var curry = require('../common/lang').curry;
|
||||
|
||||
// 检查数组支持情况
|
||||
if(typeof ArrayBuffer === 'undefined' || typeof DataView === 'undefined') {
|
||||
|
@ -10,7 +10,7 @@
|
||||
define(
|
||||
function(require) {
|
||||
var struct = require('./struct');
|
||||
var extend = require('common/lang').extend;
|
||||
var extend = require('../../common/lang').extend;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -24,8 +24,6 @@ define(
|
||||
val.endPtsOfContours.length - 1
|
||||
] + 1;
|
||||
|
||||
val.contours = contours;
|
||||
|
||||
// 获取flag标志
|
||||
var i = 0;
|
||||
while (i < contours) {
|
||||
@ -181,6 +179,7 @@ define(
|
||||
ttfglyf.empty = function() {
|
||||
var val = {};
|
||||
val.flags = [];
|
||||
val.endPtsOfContours = [];
|
||||
val.contours = 0;
|
||||
val.coordinates = [];
|
||||
val.xCoorinateOffset = 0; // x偏移
|
||||
|
@ -87,18 +87,28 @@ define(
|
||||
* @return {Object} 字符信息
|
||||
*/
|
||||
TTF.prototype.chars = function() {
|
||||
return this.ttf.chars;
|
||||
return Object.keys(this.ttf.chars);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取字符的glyf信息
|
||||
*
|
||||
* @return {Object} 字符信息
|
||||
* @return {?number} 返回glyf索引号
|
||||
*/
|
||||
TTF.prototype.getCharGlyfIndex = function(c) {
|
||||
var charCode = typeof c == 'number' ? c : c.charCodeAt(0);
|
||||
var glyfIndex = this.ttf.chars[charCode] || 0;
|
||||
return glyfIndex;
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取字符的glyf信息
|
||||
*
|
||||
* @return {?Object} 返回glyf对象
|
||||
*/
|
||||
TTF.prototype.getCharGlyf = function(c) {
|
||||
var charCode = String.fromCharCode(c);
|
||||
var glyfIndex = this.ttf.chars[charCode];
|
||||
return glyfIndex == undefined ? null : this.ttf.glyf[glyfIndex];
|
||||
var glyfIndex = this.getCharGlyfIndex(c);
|
||||
return this.ttf.glyf[glyfIndex];
|
||||
};
|
||||
|
||||
return TTF;
|
||||
|
31
src/ttf/ttf2base64.js
Normal file
31
src/ttf/ttf2base64.js
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* @file ttf2base64.js
|
||||
* @author mengke01
|
||||
* @date
|
||||
* @description
|
||||
* ttf 二进制转base64编码
|
||||
*/
|
||||
|
||||
|
||||
define(
|
||||
function(require) {
|
||||
|
||||
/**
|
||||
* ttf 二进制转base64编码
|
||||
*
|
||||
* @param {Array} arrayBuffer ArrayBuffer对象
|
||||
* @return {string} base64编码
|
||||
*/
|
||||
function ttf2base64(arrayBuffer) {
|
||||
var length = arrayBuffer.byteLength || arrayBuffer.length;
|
||||
var view = new DataView(arrayBuffer, 0, length);
|
||||
var str = '';
|
||||
for(var i = 0; i < length; i++) {
|
||||
str += String.fromCharCode(view.getUint8(i, false));
|
||||
}
|
||||
return btoa(str);
|
||||
}
|
||||
|
||||
return ttf2base64;
|
||||
}
|
||||
);
|
Loading…
x
Reference in New Issue
Block a user