svg2ttf
Version:
Converts SVG font to TTF font
130 lines (109 loc) • 3.46 kB
JavaScript
var _ = require('lodash')
var math = require('../math')
// Remove points, that looks like straight line
function simplify (contours, accuracy) {
return _.map(contours, function (contour) {
var i, curr, prev, next
var p, pPrev, pNext
// run from the end, to simplify array elements removal
for (i = contour.length - 2; i > 1; i--) {
prev = contour[i - 1]
next = contour[i + 1]
curr = contour[i]
// skip point (both oncurve & offcurve),
// if [prev,next] is straight line
if (prev.onCurve && next.onCurve) {
p = new math.Point(curr.x, curr.y)
pPrev = new math.Point(prev.x, prev.y)
pNext = new math.Point(next.x, next.y)
if (math.isInLine(pPrev, p, pNext, accuracy)) {
contour.splice(i, 1)
}
}
}
return contour
})
}
// Remove interpolateable oncurve points
// Those should be in the middle of nebor offcurve points
function interpolate (contours, accuracy) {
return _.map(contours, function (contour) {
var resContour = []
_.forEach(contour, function (point, idx) {
// Never skip first and last points
if (idx === 0 || idx === (contour.length - 1)) {
resContour.push(point)
return
}
var prev = contour[idx - 1]
var next = contour[idx + 1]
var p, pPrev, pNext
// skip interpolateable oncurve points (if exactly between previous and next offcurves)
if (!prev.onCurve && point.onCurve && !next.onCurve) {
p = new math.Point(point.x, point.y)
pPrev = new math.Point(prev.x, prev.y)
pNext = new math.Point(next.x, next.y)
if (pPrev.add(pNext).div(2).sub(p).dist() < accuracy) {
return
}
}
// keep the rest
resContour.push(point)
})
return resContour
})
}
function roundPoints (contours) {
return _.map(contours, function (contour) {
return _.map(contour, function (point) {
return { x: Math.round(point.x), y: Math.round(point.y), onCurve: point.onCurve }
})
})
}
// Remove closing point if it is the same as first point of contour.
// TTF doesn't need this point when drawing contours.
function removeClosingReturnPoints (contours) {
return _.map(contours, function (contour) {
var length = contour.length
if (length > 1 &&
contour[0].x === contour[length - 1].x &&
contour[0].y === contour[length - 1].y) {
contour.splice(length - 1)
}
return contour
})
}
function toRelative (contours) {
var prevPoint = { x: 0, y: 0 }
var resContours = []
var resContour
_.forEach(contours, function (contour) {
resContour = []
resContours.push(resContour)
_.forEach(contour, function (point) {
resContour.push({
x: point.x - prevPoint.x,
y: point.y - prevPoint.y,
onCurve: point.onCurve
})
prevPoint = point
})
})
return resContours
}
function identifier (string, littleEndian) {
var result = 0
for (var i = 0; i < string.length; i++) {
result = result << 8
var index = littleEndian ? string.length - i - 1 : i
result += string.charCodeAt(index)
}
return result
}
module.exports.interpolate = interpolate
module.exports.simplify = simplify
module.exports.roundPoints = roundPoints
module.exports.removeClosingReturnPoints = removeClosingReturnPoints
module.exports.toRelative = toRelative
module.exports.identifier = identifier