UNPKG

zoomla

Version:

16年专业研发|中文alexa排名第一的CMS品牌-基于dotNET core、功能强大,集成站群、微信开发、小程序与ERP及OA办公系统,支持国际语言和多民族语言,世界五百强与大型门户专用高端网站内核CMS系统

1,305 lines (1,113 loc) 33.4 kB
/* Copyright (C) 2001-2013 Peter Selinger. * * A javascript port of Potrace (http://potrace.sourceforge.net). * * Licensed under the GPL * * Usage * loadImageFromFile(file) : load image from File API * loadImageFromUrl(url): load image from URL * because of the same-origin policy, can not load image from another domain. * input color/grayscale image is simply converted to binary image. no pre- * process is performed. * * setParameter({para1: value, ...}) : set parameters * parameters: * turnpolicy ("black" / "white" / "left" / "right" / "minority" / "majority") * how to resolve ambiguities in path decomposition. (default: "minority") * turdsize * suppress speckles of up to this size (default: 2) * optcurve (true / false) * turn on/off curve optimization (default: true) * alphamax * corner threshold parameter (default: 1) * opttolerance * curve optimization tolerance (default: 0.2) * * process(callback) : wait for the image be loaded, then run potrace algorithm, * then call callback function. * * getSVG(size, opt_type) : return a string of generated SVG image. * result_image_size = original_image_size * size * optional parameter opt_type can be "curve" */ var Potrace = (function() { function Point(x, y) { this.x = x; this.y = y; } Point.prototype.copy = function(){ return new Point(this.x, this.y); }; function Bitmap(w, h) { this.w = w; this.h = h; this.size = w * h; this.arraybuffer = new ArrayBuffer(this.size); this.data = new Int8Array(this.arraybuffer); } Bitmap.prototype.at = function (x, y) { return (x >= 0 && x < this.w && y >=0 && y < this.h) && this.data[this.w * y + x] === 1; }; Bitmap.prototype.index = function(i) { var point = new Point(); point.y = Math.floor(i / this.w); point.x = i - point.y * this.w; return point; }; Bitmap.prototype.flip = function(x, y) { if (this.at(x, y)) { this.data[this.w * y + x] = 0; } else { this.data[this.w * y + x] = 1; } }; Bitmap.prototype.copy = function() { var bm = new Bitmap(this.w, this.h), i; for (i = 0; i < this.size; i++) { bm.data[i] = this.data[i]; } return bm; }; function Path() { this.area = 0; this.len = 0; this.curve = {}; this.pt = []; this.minX = 100000; this.minY = 100000; this.maxX= -1; this.maxY = -1; } function Curve(n) { this.n = n; this.tag = new Array(n); this.c = new Array(n * 3); this.alphaCurve = 0; this.vertex = new Array(n); this.alpha = new Array(n); this.alpha0 = new Array(n); this.beta = new Array(n); } var imgElement = document.createElement("img"), imgCanvas = document.createElement("canvas"), bm = null, pathlist = [], callback, info = { isReady: false, turnpolicy: "minority", turdsize: 2, optcurve: true, alphamax: 1, opttolerance: 0.2 }; imgElement.onload = function() { loadCanvas(); loadBm(); }; function loadImageFromFile(file) { if (info.isReady) { clear(); } imgElement.file = file; var reader = new FileReader(); reader.onload = (function(aImg) { return function(e) { aImg.src = e.target.result; }; })(imgElement); reader.readAsDataURL(file); } function loadImageFromUrl(url) { if (info.isReady) { clear(); } imgElement.src = url; } function setParameter(obj) { var key; for (key in obj) { if (obj.hasOwnProperty(key)) { info[key] = obj[key]; } } } function loadCanvas() { imgCanvas.width = imgElement.width; imgCanvas.height = imgElement.height; var ctx = imgCanvas.getContext('2d'); ctx.drawImage(imgElement, 0, 0); } function loadBm() { var ctx = imgCanvas.getContext('2d'); bm = new Bitmap(imgCanvas.width, imgCanvas.height); var imgdataobj = ctx.getImageData(0, 0, bm.w, bm.h); var l = imgdataobj.data.length, i, j, color; for (i = 0, j = 0; i < l; i += 4, j++) { color = 0.2126 * imgdataobj.data[i] + 0.7153 * imgdataobj.data[i + 1] + 0.0721 * imgdataobj.data[i + 2]; bm.data[j] = (color < 128 ? 1 : 0); } info.isReady = true; } function bmToPathlist() { var bm1 = bm.copy(), currentPoint = new Point(0, 0), path; function findNext(point) { var i = bm1.w * point.y + point.x; while (i < bm1.size && bm1.data[i] !== 1) { i++; } return i < bm1.size && bm1.index(i); } function majority(x, y) { var i, a, ct; for (i = 2; i < 5; i++) { ct = 0; for (a = -i + 1; a <= i - 1; a++) { ct += bm1.at(x + a, y + i - 1) ? 1 : -1; ct += bm1.at(x + i - 1, y + a - 1) ? 1 : -1; ct += bm1.at(x + a - 1, y - i) ? 1 : -1; ct += bm1.at(x - i, y + a) ? 1 : -1; } if (ct > 0) { return 1; } else if (ct < 0) { return 0; } } return 0; } function findPath(point) { var path = new Path(), x = point.x, y = point.y, dirx = 0, diry = 1, tmp; path.sign = bm.at(point.x, point.y) ? "+" : "-"; while (1) { path.pt.push(new Point(x, y)); if (x > path.maxX) path.maxX = x; if (x < path.minX) path.minX = x; if (y > path.maxY) path.maxY = y; if (y < path.minY) path.minY = y; path.len++; x += dirx; y += diry; path.area -= x * diry; if (x === point.x && y === point.y) break; var l = bm1.at(x + (dirx + diry - 1 ) / 2, y + (diry - dirx - 1) / 2); var r = bm1.at(x + (dirx - diry - 1) / 2, y + (diry + dirx - 1) / 2); if (r && !l) { if (info.turnpolicy === "right" || (info.turnpolicy === "black" && path.sign === '+') || (info.turnpolicy === "white" && path.sign === '-') || (info.turnpolicy === "majority" && majority(x, y)) || (info.turnpolicy === "minority" && !majority(x, y))) { tmp = dirx; dirx = -diry; diry = tmp; } else { tmp = dirx; dirx = diry; diry = -tmp; } } else if (r) { tmp = dirx; dirx = -diry; diry = tmp; } else if (!l) { tmp = dirx; dirx = diry; diry = -tmp; } } return path; } function xorPath(path){ var y1 = path.pt[0].y, len = path.len, x, y, maxX, minY, i, j; for (i = 1; i < len; i++) { x = path.pt[i].x; y = path.pt[i].y; if (y !== y1) { minY = y1 < y ? y1 : y; maxX = path.maxX; for (j = x; j < maxX; j++) { bm1.flip(j, minY); } y1 = y; } } } while (currentPoint = findNext(currentPoint)) { path = findPath(currentPoint); xorPath(path); if (path.area > info.turdsize) { pathlist.push(path); } } } function processPath() { function Quad() { this.data = [0,0,0,0,0,0,0,0,0]; } Quad.prototype.at = function(x, y) { return this.data[x * 3 + y]; }; function Sum(x, y, xy, x2, y2) { this.x = x; this.y = y; this.xy = xy; this.x2 = x2; this.y2 = y2; } 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)); } 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; } 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; } } function calcSums(path) { var i, x, y; path.x0 = path.pt[0].x; path.y0 = path.pt[0].y; path.sums = []; var s = path.sums; s.push(new Sum(0, 0, 0, 0, 0)); for(i = 0; i < path.len; i++){ x = path.pt[i].x - path.x0; y = path.pt[i].y - path.y0; s.push(new Sum(s[i].x + x, s[i].y + y, s[i].xy + x * y, s[i].x2 + x * x, s[i].y2 + y * y)); } } function calcLon(path) { var n = path.len, pt = path.pt, dir, pivk = new Array(n), nc = new Array(n), ct = new Array(4); path.lon = new Array(n); var constraint = [new Point(), new Point()], cur = new Point(), off = new Point(), dk = new Point(), foundk; var i, j, k1, a, b, c, d, k = 0; for(i = n - 1; i >= 0; i--){ if (pt[i].x != pt[k].x && pt[i].y != pt[k].y) { k = i + 1; } nc[i] = k; } for (i = n - 1; i >= 0; i--) { ct[0] = ct[1] = ct[2] = ct[3] = 0; dir = (3 + 3 * (pt[mod(i + 1, n)].x - pt[i].x) + (pt[mod(i + 1, n)].y - pt[i].y)) / 2; ct[dir]++; constraint[0].x = 0; constraint[0].y = 0; constraint[1].x = 0; constraint[1].y = 0; k = nc[i]; k1 = i; while (1) { foundk = 0; dir = (3 + 3 * sign(pt[k].x - pt[k1].x) + sign(pt[k].y - pt[k1].y)) / 2; ct[dir]++; if (ct[0] && ct[1] && ct[2] && ct[3]) { pivk[i] = k1; foundk = 1; break; } cur.x = pt[k].x - pt[i].x; cur.y = pt[k].y - pt[i].y; if (xprod(constraint[0], cur) < 0 || xprod(constraint[1], cur) > 0) { break; } if (Math.abs(cur.x) <= 1 && Math.abs(cur.y) <= 1) { } else { off.x = cur.x + ((cur.y >= 0 && (cur.y > 0 || cur.x < 0)) ? 1 : -1); off.y = cur.y + ((cur.x <= 0 && (cur.x < 0 || cur.y < 0)) ? 1 : -1); if (xprod(constraint[0], off) >= 0) { constraint[0].x = off.x; constraint[0].y = off.y; } off.x = cur.x + ((cur.y <= 0 && (cur.y < 0 || cur.x < 0)) ? 1 : -1); off.y = cur.y + ((cur.x >= 0 && (cur.x > 0 || cur.y < 0)) ? 1 : -1); if (xprod(constraint[1], off) <= 0) { constraint[1].x = off.x; constraint[1].y = off.y; } } k1 = k; k = nc[k1]; if (!cyclic(k, i, k1)) { break; } } if (foundk === 0) { dk.x = sign(pt[k].x-pt[k1].x); dk.y = sign(pt[k].y-pt[k1].y); cur.x = pt[k1].x - pt[i].x; cur.y = pt[k1].y - pt[i].y; a = xprod(constraint[0], cur); b = xprod(constraint[0], dk); c = xprod(constraint[1], cur); d = xprod(constraint[1], dk); j = 10000000; if (b < 0) { j = Math.floor(a / -b); } if (d > 0) { j = Math.min(j, Math.floor(-c / d)); } pivk[i] = mod(k1+j,n); } } j=pivk[n-1]; path.lon[n-1]=j; for (i=n-2; i>=0; i--) { if (cyclic(i+1,pivk[i],j)) { j=pivk[i]; } path.lon[i]=j; } for (i=n-1; cyclic(mod(i+1,n),j,path.lon[i]); i--) { path.lon[i] = j; } } function bestPolygon(path) { function penalty3(path, i, j) { var n = path.len, pt = path.pt, sums = path.sums; var x, y, xy, x2, y2, k, a, b, c, s, px, py, ex, ey, r = 0; if (j>=n) { j -= n; r = 1; } if (r === 0) { x = sums[j+1].x - sums[i].x; y = sums[j+1].y - sums[i].y; x2 = sums[j+1].x2 - sums[i].x2; xy = sums[j+1].xy - sums[i].xy; y2 = sums[j+1].y2 - sums[i].y2; k = j+1 - i; } else { x = sums[j+1].x - sums[i].x + sums[n].x; y = sums[j+1].y - sums[i].y + sums[n].y; x2 = sums[j+1].x2 - sums[i].x2 + sums[n].x2; xy = sums[j+1].xy - sums[i].xy + sums[n].xy; y2 = sums[j+1].y2 - sums[i].y2 + sums[n].y2; k = j+1 - i + n; } px = (pt[i].x + pt[j].x) / 2.0 - pt[0].x; py = (pt[i].y + pt[j].y) / 2.0 - pt[0].y; ey = (pt[j].x - pt[i].x); ex = -(pt[j].y - pt[i].y); a = ((x2 - 2*x*px) / k + px*px); b = ((xy - x*py - y*px) / k + px*py); c = ((y2 - 2*y*py) / k + py*py); s = ex*ex*a + 2*ex*ey*b + ey*ey*c; return Math.sqrt(s); } var i, j, m, k, n = path.len, pen = new Array(n + 1), prev = new Array(n + 1), clip0 = new Array(n), clip1 = new Array(n + 1), seg0 = new Array (n + 1), seg1 = new Array(n + 1), thispen, best, c; for (i=0; i<n; i++) { c = mod(path.lon[mod(i-1,n)]-1,n); if (c == i) { c = mod(i+1,n); } if (c < i) { clip0[i] = n; } else { clip0[i] = c; } } j = 1; for (i=0; i<n; i++) { while (j <= clip0[i]) { clip1[j] = i; j++; } } i = 0; for (j=0; i<n; j++) { seg0[j] = i; i = clip0[i]; } seg0[j] = n; m = j; i = n; for (j=m; j>0; j--) { seg1[j] = i; i = clip1[i]; } seg1[0] = 0; pen[0]=0; for (j=1; j<=m; j++) { for (i=seg1[j]; i<=seg0[j]; i++) { best = -1; for (k=seg0[j-1]; k>=clip1[i]; k--) { thispen = penalty3(path, k, i) + pen[k]; if (best < 0 || thispen < best) { prev[i] = k; best = thispen; } } pen[i] = best; } } path.m = m; path.po = new Array(m); for (i=n, j=m-1; i>0; j--) { i = prev[i]; path.po[j] = i; } } function adjustVertices(path) { function pointslope(path, i, j, ctr, dir) { var n = path.len, sums = path.sums, x, y, x2, xy, y2, k, a, b, c, lambda2, l, r=0; while (j>=n) { j-=n; r+=1; } while (i>=n) { i-=n; r-=1; } while (j<0) { j+=n; r-=1; } while (i<0) { i+=n; r+=1; } x = sums[j+1].x-sums[i].x+r*sums[n].x; y = sums[j+1].y-sums[i].y+r*sums[n].y; x2 = sums[j+1].x2-sums[i].x2+r*sums[n].x2; xy = sums[j+1].xy-sums[i].xy+r*sums[n].xy; y2 = sums[j+1].y2-sums[i].y2+r*sums[n].y2; k = j+1-i+r*n; ctr.x = x/k; ctr.y = y/k; a = (x2-x*x/k)/k; b = (xy-x*y/k)/k; c = (y2-y*y/k)/k; lambda2 = (a+c+Math.sqrt((a-c)*(a-c)+4*b*b))/2; a -= lambda2; c -= lambda2; if (Math.abs(a) >= Math.abs(c)) { l = Math.sqrt(a*a+b*b); if (l!==0) { dir.x = -b/l; dir.y = a/l; } } else { l = Math.sqrt(c*c+b*b); if (l!==0) { dir.x = -c/l; dir.y = b/l; } } if (l===0) { dir.x = dir.y = 0; } } var m = path.m, po = path.po, n = path.len, pt = path.pt, x0 = path.x0, y0 = path.y0, ctr = new Array(m), dir = new Array(m), q = new Array(m), v = new Array(3), d, i, j, k, l, s = new Point(); path.curve = new Curve(m); for (i=0; i<m; i++) { j = po[mod(i+1,m)]; j = mod(j-po[i],n)+po[i]; ctr[i] = new Point(); dir[i] = new Point(); pointslope(path, po[i], j, ctr[i], dir[i]); } for (i=0; i<m; i++) { q[i] = new Quad(); d = dir[i].x * dir[i].x + dir[i].y * dir[i].y; if (d === 0.0) { for (j=0; j<3; j++) { for (k=0; k<3; k++) { q[i].data[j * 3 + k] = 0; } } } else { v[0] = dir[i].y; v[1] = -dir[i].x; v[2] = - v[1] * ctr[i].y - v[0] * ctr[i].x; for (l=0; l<3; l++) { for (k=0; k<3; k++) { q[i].data[l * 3 + k] = v[l] * v[k] / d; } } } } var Q, w, dx, dy, det, min, cand, xmin, ymin, z; for (i=0; i<m; i++) { Q = new Quad(); w = new Point(); s.x = pt[po[i]].x-x0; s.y = pt[po[i]].y-y0; j = mod(i-1,m); for (l=0; l<3; l++) { for (k=0; k<3; k++) { Q.data[l * 3 + k] = q[j].at(l, k) + q[i].at(l, k); } } while(1) { det = Q.at(0, 0)*Q.at(1, 1) - Q.at(0, 1)*Q.at(1, 0); if (det !== 0.0) { w.x = (-Q.at(0, 2)*Q.at(1, 1) + Q.at(1, 2)*Q.at(0, 1)) / det; w.y = ( Q.at(0, 2)*Q.at(1, 0) - Q.at(1, 2)*Q.at(0, 0)) / det; break; } if (Q.at(0, 0)>Q.at(1, 1)) { v[0] = -Q.at(0, 1); v[1] = Q.at(0, 0); } else if (Q.at(1, 1)) { v[0] = -Q.at(1, 1); v[1] = Q.at(1, 0); } else { v[0] = 1; v[1] = 0; } d = v[0] * v[0] + v[1] * v[1]; v[2] = - v[1] * s.y - v[0] * s.x; for (l=0; l<3; l++) { for (k=0; k<3; k++) { Q.data[l * 3 + k] += v[l] * v[k] / d; } } } dx = Math.abs(w.x-s.x); dy = Math.abs(w.y-s.y); if (dx <= 0.5 && dy <= 0.5) { path.curve.vertex[i] = new Point(w.x+x0, w.y+y0); continue; } min = quadform(Q, s); xmin = s.x; ymin = s.y; if (Q.at(0, 0) !== 0.0) { for (z=0; z<2; z++) { w.y = s.y-0.5+z; w.x = - (Q.at(0, 1) * w.y + Q.at(0, 2)) / Q.at(0, 0); dx = Math.abs(w.x-s.x); cand = quadform(Q, w); if (dx <= 0.5 && cand < min) { min = cand; xmin = w.x; ymin = w.y; } } } if (Q.at(1, 1) !== 0.0) { for (z=0; z<2; z++) { w.x = s.x-0.5+z; w.y = - (Q.at(1, 0) * w.x + Q.at(1, 2)) / Q.at(1, 1); dy = Math.abs(w.y-s.y); cand = quadform(Q, w); if (dy <= 0.5 && cand < min) { min = cand; xmin = w.x; ymin = w.y; } } } for (l=0; l<2; l++) { for (k=0; k<2; k++) { w.x = s.x-0.5+l; w.y = s.y-0.5+k; cand = quadform(Q, w); if (cand < min) { min = cand; xmin = w.x; ymin = w.y; } } } path.curve.vertex[i] = new Point(xmin + x0, ymin + y0); } } function reverse(path) { var curve = path.curve, m = curve.n, v = curve.vertex, i, j, tmp; for (i=0, j=m-1; i<j; i++, j--) { tmp = v[i]; v[i] = v[j]; v[j] = tmp; } } function smooth(path) { var m = path.curve.n, curve = path.curve; var i, j, k, dd, denom, alpha, p2, p3, p4; for (i=0; i<m; i++) { j = mod(i+1, m); k = mod(i+2, m); p4 = interval(1/2.0, curve.vertex[k], curve.vertex[j]); denom = ddenom(curve.vertex[i], curve.vertex[k]); if (denom !== 0.0) { dd = dpara(curve.vertex[i], curve.vertex[j], curve.vertex[k]) / denom; dd = Math.abs(dd); alpha = dd>1 ? (1 - 1.0/dd) : 0; alpha = alpha / 0.75; } else { alpha = 4/3.0; } curve.alpha0[j] = alpha; if (alpha >= info.alphamax) { curve.tag[j] = "CORNER"; curve.c[3 * j + 1] = curve.vertex[j]; curve.c[3 * j + 2] = p4; } else { if (alpha < 0.55) { alpha = 0.55; } else if (alpha > 1) { alpha = 1; } p2 = interval(0.5+0.5*alpha, curve.vertex[i], curve.vertex[j]); p3 = interval(0.5+0.5*alpha, curve.vertex[k], curve.vertex[j]); curve.tag[j] = "CURVE"; curve.c[3 * j + 0] = p2; curve.c[3 * j + 1] = p3; curve.c[3 * j + 2] = p4; } curve.alpha[j] = alpha; curve.beta[j] = 0.5; } curve.alphacurve = 1; } function optiCurve(path) { function Opti(){ this.pen = 0; this.c = [new Point(), new Point()]; this.t = 0; this.s = 0; this.alpha = 0; } function opti_penalty(path, i, j, res, opttolerance, convc, areac) { var m = path.curve.n, curve = path.curve, vertex = curve.vertex, k, k1, k2, conv, i1, area, alpha, d, d1, d2, p0, p1, p2, p3, pt, A, R, A1, A2, A3, A4, s, t; if (i==j) { return 1; } k = i; i1 = mod(i+1, m); k1 = mod(k+1, m); conv = convc[k1]; if (conv === 0) { return 1; } d = ddist(vertex[i], vertex[i1]); for (k=k1; k!=j; k=k1) { k1 = mod(k+1, m); k2 = mod(k+2, m); if (convc[k1] != conv) { return 1; } if (sign(cprod(vertex[i], vertex[i1], vertex[k1], vertex[k2])) != conv) { return 1; } if (iprod1(vertex[i], vertex[i1], vertex[k1], vertex[k2]) < d * ddist(vertex[k1], vertex[k2]) * -0.999847695156) { return 1; } } p0 = curve.c[mod(i,m) * 3 + 2].copy(); p1 = vertex[mod(i+1,m)].copy(); p2 = vertex[mod(j,m)].copy(); p3 = curve.c[mod(j,m) * 3 + 2].copy(); area = areac[j] - areac[i]; area -= dpara(vertex[0], curve.c[i * 3 + 2], curve.c[j * 3 + 2])/2; if (i>=j) { area += areac[m]; } A1 = dpara(p0, p1, p2); A2 = dpara(p0, p1, p3); A3 = dpara(p0, p2, p3); A4 = A1+A3-A2; if (A2 == A1) { return 1; } t = A3/(A3-A4); s = A2/(A2-A1); A = A2 * t / 2.0; if (A === 0.0) { return 1; } R = area / A; alpha = 2 - Math.sqrt(4 - R / 0.3); res.c[0] = interval(t * alpha, p0, p1); res.c[1] = interval(s * alpha, p3, p2); res.alpha = alpha; res.t = t; res.s = s; p1 = res.c[0].copy(); p2 = res.c[1].copy(); res.pen = 0; for (k=mod(i+1,m); k!=j; k=k1) { k1 = mod(k+1,m); t = tangent(p0, p1, p2, p3, vertex[k], vertex[k1]); if (t<-0.5) { return 1; } pt = bezier(t, p0, p1, p2, p3); d = ddist(vertex[k], vertex[k1]); if (d === 0.0) { return 1; } d1 = dpara(vertex[k], vertex[k1], pt) / d; if (Math.abs(d1) > opttolerance) { return 1; } if (iprod(vertex[k], vertex[k1], pt) < 0 || iprod(vertex[k1], vertex[k], pt) < 0) { return 1; } res.pen += d1 * d1; } for (k=i; k!=j; k=k1) { k1 = mod(k+1,m); t = tangent(p0, p1, p2, p3, curve.c[k * 3 + 2], curve.c[k1 * 3 + 2]); if (t<-0.5) { return 1; } pt = bezier(t, p0, p1, p2, p3); d = ddist(curve.c[k * 3 + 2], curve.c[k1 * 3 + 2]); if (d === 0.0) { return 1; } d1 = dpara(curve.c[k * 3 + 2], curve.c[k1 * 3 + 2], pt) / d; d2 = dpara(curve.c[k * 3 + 2], curve.c[k1 * 3 + 2], vertex[k1]) / d; d2 *= 0.75 * curve.alpha[k1]; if (d2 < 0) { d1 = -d1; d2 = -d2; } if (d1 < d2 - opttolerance) { return 1; } if (d1 < d2) { res.pen += (d1 - d2) * (d1 - d2); } } return 0; } var curve = path.curve, m = curve.n, vert = curve.vertex, pt = new Array(m + 1), pen = new Array(m + 1), len = new Array(m + 1), opt = new Array(m + 1), om, i,j,r, o = new Opti(), p0, i1, area, alpha, ocurve, s, t; var convc = new Array(m), areac = new Array(m + 1); for (i=0; i<m; i++) { if (curve.tag[i] == "CURVE") { convc[i] = sign(dpara(vert[mod(i-1,m)], vert[i], vert[mod(i+1,m)])); } else { convc[i] = 0; } } area = 0.0; areac[0] = 0.0; p0 = curve.vertex[0]; for (i=0; i<m; i++) { i1 = mod(i+1, m); if (curve.tag[i1] == "CURVE") { alpha = curve.alpha[i1]; area += 0.3 * alpha * (4-alpha) * dpara(curve.c[i * 3 + 2], vert[i1], curve.c[i1 * 3 + 2])/2; area += dpara(p0, curve.c[i * 3 + 2], curve.c[i1 * 3 + 2])/2; } areac[i+1] = area; } pt[0] = -1; pen[0] = 0; len[0] = 0; for (j=1; j<=m; j++) { pt[j] = j-1; pen[j] = pen[j-1]; len[j] = len[j-1]+1; for (i=j-2; i>=0; i--) { r = opti_penalty(path, i, mod(j,m), o, info.opttolerance, convc, areac); if (r) { break; } if (len[j] > len[i]+1 || (len[j] == len[i]+1 && pen[j] > pen[i] + o.pen)) { pt[j] = i; pen[j] = pen[i] + o.pen; len[j] = len[i] + 1; opt[j] = o; o = new Opti(); } } } om = len[m]; ocurve = new Curve(om); s = new Array(om); t = new Array(om); j = m; for (i=om-1; i>=0; i--) { if (pt[j]==j-1) { ocurve.tag[i] = curve.tag[mod(j,m)]; ocurve.c[i * 3 + 0] = curve.c[mod(j,m) * 3 + 0]; ocurve.c[i * 3 + 1] = curve.c[mod(j,m) * 3 + 1]; ocurve.c[i * 3 + 2] = curve.c[mod(j,m) * 3 + 2]; ocurve.vertex[i] = curve.vertex[mod(j,m)]; ocurve.alpha[i] = curve.alpha[mod(j,m)]; ocurve.alpha0[i] = curve.alpha0[mod(j,m)]; ocurve.beta[i] = curve.beta[mod(j,m)]; s[i] = t[i] = 1.0; } else { ocurve.tag[i] = "CURVE"; ocurve.c[i * 3 + 0] = opt[j].c[0]; ocurve.c[i * 3 + 1] = opt[j].c[1]; ocurve.c[i * 3 + 2] = curve.c[mod(j,m) * 3 + 2]; ocurve.vertex[i] = interval(opt[j].s, curve.c[mod(j,m) * 3 + 2], vert[mod(j,m)]); ocurve.alpha[i] = opt[j].alpha; ocurve.alpha0[i] = opt[j].alpha; s[i] = opt[j].s; t[i] = opt[j].t; } j = pt[j]; } for (i=0; i<om; i++) { i1 = mod(i+1,om); ocurve.beta[i] = s[i] / (s[i] + t[i1]); } ocurve.alphacurve = 1; path.curve = ocurve; } for (var i = 0; i < pathlist.length; i++) { var path = pathlist[i]; calcSums(path); calcLon(path); bestPolygon(path); adjustVertices(path); if (path.sign === "-") { reverse(path); } smooth(path); if (info.optcurve) { optiCurve(path); } } } function process(c) { if (c) { callback = c; } if (!info.isReady) { setTimeout(process, 100); } bmToPathlist(); processPath(); callback(); callback = null; } function clear() { bm = null; pathlist = []; callback = null; info.isReady = false; } function getSVG(size, opt_type) { function path(curve) { function bezier(i) { var b = 'C ' + (curve.c[i * 3 + 0].x * size).toFixed(3) + ' ' + (curve.c[i * 3 + 0].y * size).toFixed(3) + ','; b += (curve.c[i * 3 + 1].x * size).toFixed(3) + ' ' + (curve.c[i * 3 + 1].y * size).toFixed(3) + ','; b += (curve.c[i * 3 + 2].x * size).toFixed(3) + ' ' + (curve.c[i * 3 + 2].y * size).toFixed(3) + ' '; return b; } function segment(i) { var s = 'L ' + (curve.c[i * 3 + 1].x * size).toFixed(3) + ' ' + (curve.c[i * 3 + 1].y * size).toFixed(3) + ' '; s += (curve.c[i * 3 + 2].x * size).toFixed(3) + ' ' + (curve.c[i * 3 + 2].y * size).toFixed(3) + ' '; return s; } var n = curve.n, i; var p = 'M' + (curve.c[(n - 1) * 3 + 2].x * size).toFixed(3) + ' ' + (curve.c[(n - 1) * 3 + 2].y * size).toFixed(3) + ' '; for (i = 0; i < n; i++) { if (curve.tag[i] === "CURVE") { p += bezier(i); } else if (curve.tag[i] === "CORNER") { p += segment(i); } } //p += return p; } var w = bm.w * size, h = bm.h * size, len = pathlist.length, c, i, strokec, fillc, fillrule; var svg = '<svg id="svg" version="1.1" width="' + w + '" height="' + h + '" xmlns="http://www.w3.org/2000/svg">'; svg += '<path d="'; for (i = 0; i < len; i++) { c = pathlist[i].curve; svg += path(c); } if (opt_type === "curve") { strokec = "black"; fillc = "none"; fillrule = ''; } else { strokec = "none"; fillc = "black"; fillrule = ' fill-rule="evenodd"'; } svg += '" stroke="' + strokec + '" fill="' + fillc + '"' + fillrule + '/></svg>'; return svg; } return{ loadImageFromFile: loadImageFromFile, loadImageFromUrl: loadImageFromUrl, setParameter: setParameter, process: process, getSVG: getSVG, img: imgElement }; })();