add fit glyf

This commit is contained in:
kekee000
2015-03-25 19:31:34 +08:00
parent 2efb29fec0
commit 72b8d3ce4c
10 changed files with 311 additions and 160 deletions

75
demo/fitGlyf.html Normal file
View File

@@ -0,0 +1,75 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>canvas读取图片</title>
<script src="../dep/esl.js"></script>
<script src="../dep/jquery.min.js"></script>
<script src="../dep/clipper.js"></script>
<script src="../dep/hidpi-canvas.js"></script>
<link rel="stylesheet" type="text/css" href="./css/editor.css">
<style>
body {
margin: 0;
padding: 0;
}
#points, #points-break, #canvas {
position: absolute;
left: 0;
top: 40px;
width: 800px;
height: 800px;
}
#points i,
#points-break i {
position: absolute;
width: 1px;
height: 1px;
background: #ddd;
}
#points-break i.break {
width: 2px;
height: 2px;
background: red;
}
#points-break i.inflection {
width: 1px;
height: 1px;
background: green;
}
#render-view {
margin-left: 800px;
margin-top: 40px;
width: auto;
height: 800px;
}
</style>
</head>
<body>
<input id="upload-file" type="file">
<div id="points" width="800" height="800"></div>
<div id="points-break" width="800" height="800"></div>
<canvas id="canvas" width="800" height="800"></canvas>
<div id="render-view" class="render-view glyf-editor" oncontextMenu="return false"></div>
<script>
require.config({
baseUrl: '../src',
paths: {
demo: '../demo/js',
}
});
define('jquery', $);
define('ClipperLib', window.ClipperLib);
</script>
<script>require(['demo/fitGlyf'])</script>
</body>
</html>

View File

@@ -8,7 +8,7 @@ define(
var fitBezier = require('graphics/image/fitBezier');
var findBreakPoints = require('graphics/image/findBreakPoints');
var pathUtil = require('graphics/pathUtil');
var data = require('demo/../data/image-contours1');
var data = require('demo/../data/image-contours2');
var drawPath = require('render/util/drawPath');
var entry = {

View File

@@ -72,54 +72,6 @@ define(
var radius = dist(points[0], points[1]);
ctx.arc(points[0].x, points[0].y, radius, 0, 180);
ctx.stroke();
// var curvePoints = [];
// var count = 40;
// var tSegment = 1 / count;
// for (var i = 0; i < count; i++) {
// var t = tSegment * i;
// curvePoints.push({
// x: points[0].x * B0(t) + points[1].x * B1(t) + points[2].x * B2(t) + points[3].x * B3(t),
// y: points[0].y * B0(t) + points[1].y * B1(t) + points[2].y * B2(t) + points[3].y * B3(t)
// });
// }
// ctx.fillStyle='green';
// for (var i = 0; i < count; i++) {
// ctx.fillRect(curvePoints[i].x, curvePoints[i].y, 2, 2);
// }
// var result = fitCurve(lang.clone(curvePoints), count);
// result.unshift(points[0]);
// //console.log(result);
// ctx.beginPath();
// ctx.strokeStyle='blue';
// //ctx.translate(0, 10);
// ctx.moveTo(result[0].x, result[0].y);
// for (var i = 1; i < result.length - 1; i+=3) {
// ctx.bezierCurveTo(result[i].x, result[i].y, result[i + 1].x, result[i + 1].y, result[i + 2].x, result[i + 2].y);
// ctx.moveTo(result[i + 2].x, result[i + 2].y);
// }
// ctx.stroke();
// var bezierResult = fitBezier(lang.clone(curvePoints));
// bezierResult.unshift(curvePoints[0]);
// ctx.beginPath();
// ctx.strokeStyle='yellow';
// //ctx.translate(0, 10);
// ctx.moveTo(bezierResult[0].x, bezierResult[0].y);
// var last = bezierResult.length - 1;
// console.log(bezierResult.length);
// for (var i = 1; i < last; i+=2) {
// ctx.quadraticCurveTo(bezierResult[i].x, bezierResult[i].y, bezierResult[i + 1].x, bezierResult[i + 1].y);
// ctx.moveTo(bezierResult[i + 1].x, bezierResult[i + 1].y);
// }
// ctx.stroke();
//ctx.translate(0, -20);
}
draw();

View File

@@ -6,108 +6,10 @@
define(
function (require) {
var fitBezier = require('graphics/image/fitBezier');
var findBreakPoints = require('graphics/image/findBreakPoints');
var pathUtil = require('graphics/pathUtil');
var vector = require('graphics/vector');
var data = require('demo/../data/image-contours1');
var fitContour = require('graphics/image/fitContour');
var data = require('demo/../data/image-contours2');
var drawPath = require('render/util/drawPath');
var bezierCurvePointsArray = [];
function fitContour(data) {
data = pathUtil.scale(data, 10);
var breakPoints = findBreakPoints(data);
breakPoints.forEach(function (p) {
console.log(p.right);
});
var resultContour = [];
var isLast;
var start;
var end;
var tHat1Point;
for (var i = 0, l = breakPoints.length; i < l; i++) {
isLast = i === l - 1;
start = breakPoints[i];
end = breakPoints[ isLast ? 0 : i + 1];
resultContour.push({
x: start.x,
y: start.y,
onCurve: true
});
if (start.right !== 1) {
if (isLast) {
var curvePoints = data.slice(start.index).concat(data.slice(0, end.index));
}
else {
var curvePoints = data.slice(start.index, end.index + 1);
}
var bezierCurvePoints = [];
var curvePointsLast = curvePoints.length - 1;
if (curvePoints.length > 200) {
var derive = Math.floor(curvePoints.length / 10);
bezierCurvePoints = curvePoints.filter(function (p, index) {
return index === 0 || index === curvePointsLast || p.index % derive === 0;
});
}
else if (curvePoints.length > 30) {
var derive = Math.floor(curvePoints.length / 5);
bezierCurvePoints = curvePoints.filter(function (p, index) {
return index === 0 || index === curvePointsLast || p.index % derive === 0;
});
}
else {
bezierCurvePoints = curvePoints.filter(function (p, index) {
return index === 0 || index === curvePointsLast || p.index % 5 === 0;
});
}
if ((start.tangency || start.inflexion) && tHat1Point) {
tHat1 = vector.normalize({
x: start.x - tHat1Point.x,
y: start.y - tHat1Point.y
});
}
else {
tHat1 = null;
}
bezierCurvePoints.forEach(function (p) {
bezierCurvePointsArray.push(p);
});
var bezierCurve = fitBezier(bezierCurvePoints, 10, tHat1);
if (bezierCurve.length) {
bezierCurve.forEach(function (p) {
resultContour.push(p);
});
tHat1Point = bezierCurve[bezierCurve.length - 2];
}
else {
tHat1Point = null;
}
}
else {
tHat1Point = start;
}
}
resultContour = pathUtil.scale(resultContour, 0.1);
data = pathUtil.scale(data, 0.1);
return resultContour;
}
var entry = {
/**
@@ -132,13 +34,9 @@ define(
$('#points').html(html);
html = '';
bezierCurvePointsArray.forEach(function (p) {
html += '<i class="mark" style="left:'+p.x+'px;top:'+p.y+'px;"></i>';
});
var ctx = $('#canvas').get(0).getContext('2d');
ctx.strokeStyle = 'yellow';
ctx.strokeStyle = 'pink';
contours.forEach(function (contour) {
for (var i = 0, l = contour.length; i < l; i++) {

119
demo/js/fitGlyf.js Normal file
View File

@@ -0,0 +1,119 @@
/**
* @file 拟合图像字形
* @author mengke01(kekee000@gmail.com)
*/
define(
function (require) {
var fitContour = require('graphics/image/fitContour');
var image2Values = require('graphics/image/image2Values');
var findContours = require('graphics/image/findContours');
var computeBoundingBox = require('graphics/computeBoundingBox');
var pathAdjust = require('graphics/pathAdjust');
var drawPath = require('render/util/drawPath');
var data = require('demo/../data/image-contours2');
var editor = require('editor/main');
var ctx = null;
function fitGlyf(data) {
var html = '';
var contours = [];
data.forEach(function(contour) {
contour.forEach(function (p) {
html += '<i style="left:'+p.x+'px;top:'+p.y+'px;"></i>';
});
contours.push(fitContour(contour));
});
$('#points').html(html);
html = '';
ctx.beginPath();
ctx.clearRect(0,0, 1000, 1000);
ctx.strokeStyle = 'pink';
contours.forEach(function (contour) {
for (var i = 0, l = contour.length; i < l; i++) {
html += '<i style="left:'+contour[i].x+'px;top:'+contour[i].y+'px;" class="break"></i>';
}
drawPath(ctx, contour);
});
ctx.stroke();
$('#points-break').html(html);
var bound = computeBoundingBox.computePath.apply(null, contours);
window.editor.setFont({
contours: contours.map(function (contour) {
pathAdjust(contour, 1, -1);
pathAdjust(contour, 1, 1, 0, bound.height);
return contour;
})
});
}
function findImageContours(imgData) {
var result = image2Values(imgData);
var contours = findContours(result);
fitGlyf(contours);
}
function onUpFileChange(e) {
var file = e.target.files[0];
var reader = new FileReader();
reader.onload = function(e) {
var image = new Image();
image.onload = function () {
ctx.clearRect(0,0, 1000, 1000);
ctx.drawImage(image, 0, 0, image.width, image.height);
findImageContours(ctx.getImageData(0, 0, image.width, image.height));
};
image.src = e.target.result;
}
reader.onerror = function(e) {
console.error(e);
};
reader.readAsDataURL(file);
}
var entry = {
/**
* 初始化
*/
init: function () {
window.editor = editor.create($('#render-view').get(0));
var upFile = document.getElementById('upload-file');
upFile.addEventListener('change', onUpFileChange);
ctx = $('#canvas').get(0).getContext('2d');
if (data) {
data.forEach(function(contour) {
contour.splice(contour.length - 1, 1);
});
fitGlyf(data);
}
}
};
entry.init();
return entry;
}
);

View File

@@ -30,7 +30,7 @@ define(
}
function isLine(p0, p1, p) {
return 1 - absCos(p0, p1, p) < 0.01;
return 1 - absCos(p0, p1, p) < 0.004;
}
function isPerfectLine(p0, p1, p) {
@@ -212,7 +212,9 @@ define(
breakPoints = removeInflexionPoint(breakPoints, contour);
return breakPoints;
return breakPoints.sort(function (a, b) {
return a.index - b.index;
});
}
/**

View File

@@ -99,7 +99,7 @@ define(
x: x,
y: y
}, true);
contours.push(contour);
contour && contours.push(contour);
}
}
@@ -111,7 +111,7 @@ define(
x: x - 1,
y: y
}, true);
contours.push(contour.reverse());
contour && contours.push(contour.reverse());
}
}
}

View File

@@ -0,0 +1,105 @@
/**
* @file 根据关键点数据拟合轮廓
* @author mengke01(kekee000@gmail.com)
*/
define(
function (require) {
var fitBezier = require('graphics/image/fitBezier');
var findBreakPoints = require('graphics/image/findBreakPoints');
var pathUtil = require('graphics/pathUtil');
var vector = require('graphics/vector');
function fitContour(data) {
data = pathUtil.scale(data, 10);
var breakPoints = findBreakPoints(data);
var resultContour = [];
var isLast;
var start;
var end;
var curvePoints;
var tHat1Point;
for (var i = 0, l = breakPoints.length; i < l; i++) {
isLast = i === l - 1;
start = breakPoints[i];
end = breakPoints[ isLast ? 0 : i + 1];
resultContour.push({
x: start.x,
y: start.y,
onCurve: true
});
if (start.right !== 1) {
if (isLast) {
curvePoints = data.slice(start.index).concat(data.slice(0, end.index));
}
else {
curvePoints = data.slice(start.index, end.index + 1);
}
var bezierCurvePoints = [];
var curvePointsLast = curvePoints.length - 1;
if (curvePoints.length > 200) {
var derive = Math.floor(curvePoints.length / 20);
bezierCurvePoints = curvePoints.filter(function (p, index) {
return index === 0 || index === curvePointsLast || p.index % derive === 0;
});
}
else if (curvePoints.length > 40) {
var derive = Math.floor(curvePoints.length / 10);
bezierCurvePoints = curvePoints.filter(function (p, index) {
return index === 0 || index === curvePointsLast || p.index % derive === 0;
});
}
else {
bezierCurvePoints = curvePoints.filter(function (p, index) {
return index === 0 || index === curvePointsLast || p.index % 5 === 0;
});
}
if (start.tangency && tHat1Point) {
tHat1 = vector.normalize({
x: start.x - tHat1Point.x,
y: start.y - tHat1Point.y
});
}
else {
tHat1 = null;
}
var bezierCurve = fitBezier(bezierCurvePoints, 10, tHat1);
if (bezierCurve.length) {
bezierCurve.forEach(function (p) {
resultContour.push(p);
});
tHat1Point = bezierCurve[bezierCurve.length - 2];
}
else {
tHat1Point = null;
}
}
else {
tHat1Point = start;
}
}
resultContour = pathUtil.scale(resultContour, 0.1);
data = pathUtil.scale(data, 0.1);
return resultContour;
}
return fitContour;
}
);

View File

@@ -267,8 +267,8 @@ define(
/* Generate control vertices for Q'' */
for (i = 0; i <= 1; i++) {
Q2[i] = {
x: (Q[i + 1].x - Q[i].x) * 2.0,
y: (Q[i + 1].y - Q[i].y) * 2.0
x: (Q[i + 1].x - Q[i].x) * 6.0,
y: (Q[i + 1].y - Q[i].y) * 6.0
};
}

BIN
test/ecomfe.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB