UNPKG

image-vectorizer

Version:

Potrace in Javascript, for NodeJS and Browser

307 lines (242 loc) 5.66 kB
import Point from "./types/Point.js" var attrRegexps = {} function getAttrRegexp(attrName) { if (attrRegexps[attrName]) { return attrRegexps[attrName] } attrRegexps[attrName] = new RegExp(" " + attrName + '="((?:\\\\(?=")"|[^"])+)"', "i") return attrRegexps[attrName] } function setHtmlAttribute(html, attrName, value) { var attr = " " + attrName + '="' + value + '"' if (html.indexOf(" " + attrName + '="') === -1) { html = html.replace(/<[a-z]+/i, function (beginning) { return beginning + attr }) } else { html = html.replace(getAttrRegexp(attrName), attr) } return html } function fixed(number) { return number.toFixed(3).replace(".000", "") } function mod(a, n) { return a >= n ? a % n : a >= 0 ? a : n - 1 - ((-1 - a) % n) } function xprod(p1, p2) { return p1.x * p2.y - p1.y * p2.x } function cyclic(a, b, c) { if (a <= c) { return a <= b && b < c } else { return a <= b || b < c } } function sign(i) { return i > 0 ? 1 : i < 0 ? -1 : 0 } function quadform(Q, w) { var v = new Array(3), i, j, sum v[0] = w.x v[1] = w.y v[2] = 1 sum = 0.0 for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { sum += v[i] * Q.at(i, j) * v[j] } } return sum } function interval(lambda, a, b) { var res = new Point() res.x = a.x + lambda * (b.x - a.x) res.y = a.y + lambda * (b.y - a.y) return res } function dorth_infty(p0, p2) { var r = new Point() r.y = sign(p2.x - p0.x) r.x = -sign(p2.y - p0.y) return r } function ddenom(p0, p2) { var r = dorth_infty(p0, p2) return r.y * (p2.x - p0.x) - r.x * (p2.y - p0.y) } function dpara(p0, p1, p2) { var x1, y1, x2, y2 x1 = p1.x - p0.x y1 = p1.y - p0.y x2 = p2.x - p0.x y2 = p2.y - p0.y return x1 * y2 - x2 * y1 } function cprod(p0, p1, p2, p3) { var x1, y1, x2, y2 x1 = p1.x - p0.x y1 = p1.y - p0.y x2 = p3.x - p2.x y2 = p3.y - p2.y return x1 * y2 - x2 * y1 } function iprod(p0, p1, p2) { var x1, y1, x2, y2 x1 = p1.x - p0.x y1 = p1.y - p0.y x2 = p2.x - p0.x y2 = p2.y - p0.y return x1 * x2 + y1 * y2 } function iprod1(p0, p1, p2, p3) { var x1, y1, x2, y2 x1 = p1.x - p0.x y1 = p1.y - p0.y x2 = p3.x - p2.x y2 = p3.y - p2.y return x1 * x2 + y1 * y2 } function ddist(p, q) { return Math.sqrt((p.x - q.x) * (p.x - q.x) + (p.y - q.y) * (p.y - q.y)) } export default { luminance: function (r, g, b) { return Math.round(0.2126 * r + 0.7153 * g + 0.0721 * b) }, between: function (val, min, max) { return val >= min && val <= max }, clamp: function (val, min, max) { return Math.min(max, Math.max(min, val)) }, isNumber: function (val) { return typeof val === "number" }, setHtmlAttr: setHtmlAttribute, /** * Generates path instructions for given curve * * @param {Curve} curve * @param {Number} [scale] * @returns {string} */ renderCurve: function (curve, scale) { scale = scale || { x: 1, y: 1 } var startingPoint = curve.c[(curve.n - 1) * 3 + 2] var path = ["M " + fixed(startingPoint.x * scale.x) + " " + fixed(startingPoint.y * scale.y)] curve.tag.forEach(function (tag, i) { var i3 = i * 3 var p0 = curve.c[i3] var p1 = curve.c[i3 + 1] var p2 = curve.c[i3 + 2] if (tag === "CURVE") { path.push( "C " + fixed(p0.x * scale.x) + " " + fixed(p0.y * scale.y) + ", " + fixed(p1.x * scale.x) + " " + fixed(p1.y * scale.y) + ", " + fixed(p2.x * scale.x) + " " + fixed(p2.y * scale.y) ) } else if (tag === "CORNER") { path.push( "L " + fixed(p1.x * scale.x) + " " + fixed(p1.y * scale.y) + " " + fixed(p2.x * scale.x) + " " + fixed(p2.y * scale.y) ) } }) return path.join(" ") }, bezier: function bezier(t, p0, p1, p2, p3) { var s = 1 - t, res = new Point() res.x = s * s * s * p0.x + 3 * (s * s * t) * p1.x + 3 * (t * t * s) * p2.x + t * t * t * p3.x res.y = s * s * s * p0.y + 3 * (s * s * t) * p1.y + 3 * (t * t * s) * p2.y + t * t * t * p3.y return res }, tangent: function tangent(p0, p1, p2, p3, q0, q1) { var A, B, C, a, b, c, d, s, r1, r2 A = cprod(p0, p1, q0, q1) B = cprod(p1, p2, q0, q1) C = cprod(p2, p3, q0, q1) a = A - 2 * B + C b = -2 * A + 2 * B c = A d = b * b - 4 * a * c if (a === 0 || d < 0) { return -1.0 } s = Math.sqrt(d) r1 = (-b + s) / (2 * a) r2 = (-b - s) / (2 * a) if (r1 >= 0 && r1 <= 1) { return r1 } else if (r2 >= 0 && r2 <= 1) { return r2 } else { return -1.0 } }, getImageData: async function (imageSrc, callback = null) { return new Promise((resolve, reject) => { // Create an image object const img = new Image() img.crossOrigin = "anonymous" // Handle CORS if needed img.src = imageSrc img.onload = () => { // Create a canvas dynamically const canvas = document.createElement("canvas") const ctx = canvas.getContext("2d") // Set canvas size to match the image canvas.width = img.width canvas.height = img.height console.log(img.width, img.height) // Draw the image on the canvas ctx.drawImage(img, 0, 0) // Get image data const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height) // Return image data if (callback) { callback(null, imageData) } resolve(imageData) } img.onerror = (err) => { if (callback) { callback(err, null) } reject(err) } }) }, mod: mod, xprod: xprod, cyclic: cyclic, sign: sign, quadform: quadform, interval: interval, dorth_infty: dorth_infty, ddenom: ddenom, dpara: dpara, cprod: cprod, iprod: iprod, iprod1: iprod1, ddist: ddist }