add fit glyf
This commit is contained in:
75
demo/fitGlyf.html
Normal file
75
demo/fitGlyf.html
Normal 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>
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
119
demo/js/fitGlyf.js
Normal 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;
|
||||
}
|
||||
);
|
||||
@@ -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;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
105
src/graphics/image/fitContour.js
Normal file
105
src/graphics/image/fitContour.js
Normal 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;
|
||||
}
|
||||
);
|
||||
@@ -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
BIN
test/ecomfe.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.6 KiB |
Reference in New Issue
Block a user