/**
* Ah, JavaScript from 1998... when JS was still a pretty shitty language,
* syntactically, and things that have simple utility APIs today still
* required you to write out all the code yourself.
*
* Seriously: wtf, Adobe?
**/
// First: functions that do what modern JS already does.
Array.prototype.map = function(f) {
var retArr = [];
for (var i = 0, e = this.length; i < e; i++) {
retArr[i] = f(this[i], i);
}
return retArr;
};
Array.prototype.forEach = function(f) {
this.map(f);
};
Array.from = function(iterable) {
var retArr = [];
for (var i = 0, e = iterable.length; i < e; i++) {
retArr.push(iterable[i]);
}
return retArr;
}
//
// Also we'll need some custom objects.
//
var Point = function (kind, x, y) {
this.kind = kind;
this.x = x;
this.y = y;
}
Point.prototype = {
toString: function () {
var base = [this.kind];
if (this.in) {
base = base.concat(['(', this.in.x, this.in.y, ')']);
}
base = base.concat([this.x, this.y]);
if (this.out) {
base = base.concat(['(', this.out.x, this.out.y, ')']);
}
return base.join(' ');
}
}
var BBox = function () {
this.mx = 9999999;
this.my = 9999999;
this.MX = -9999999;
this.MY = -9999999;
};
BBox.prototype = {
grow: function (p) {
if (!p) return;
if (p.x < this.mx) { this.mx = p.x; }
if (p.y < this.my) { this.my = p.y; }
if (p.x > this.MX) { this.MX = p.x; }
if (p.y > this.MY) { this.MY = p.y; }
this.grow(p.in);
this.grow(p.out);
}
}
//
// And with that out of the way, the actual script:
//
var pointTypes = {
'PointKind.CORNERPOINT': 'P',
'PointKind.SMOOTHPOINT': 'C'
};
// filewrite function
function writeToFile(data) {
var path = '/';
// can we get a file location from the current document?
try { path = app.activeDocument.path; } catch (e) { }
var dir = Folder(path);
var file = dir.saveDlg('', '.svg', true);
if (!file) return false;
var mode = 'w';
file.open(mode);
file.write(data);
file.close(mode);
return file.toString();
}
// convert a PathPoint to a real object.
function improvePoint(point) {
var kind = pointTypes[point.kind];
var coord = point.anchor;
var x = Math.round(coord[0]);
var y = Math.round(coord[1]);
var obj = new Point(kind, x, y);
if (kind === 'C') {
var d;
if (point.leftDirection) {
d = point.leftDirection.map(Math.round);
obj.out = { x: d[0], y: d[1] };
}
if (point.rightDirection) {
d = point.rightDirection.map(Math.round);
obj.in = { x: d[0], y: d[1] };
}
}
return obj;
}
// convert all points in a subpath to easier to parse form
function handleSubPath(subpath) {
var pathPoints = Array.from(subpath.pathPoints);
return pathPoints.map(improvePoint);
};
// convert all subpaths in a path to easier to walk form
function handlePath(path) {
var subPaths = Array.from(path.subPathItems);
return subPaths.map(handleSubPath);
};
// convert all paths in a document to easier to walk form.
function convertPaths(pathItems) {
var paths = Array.from(pathItems);
return paths.map(handlePath);
}
// turn a subpath of improved points into an SVG path
function formSVGpath(subpath, bbox) {
var p0 = subpath[0];
var path = ['M', p0.x, p0.y];
// we want to close this path:
subpath.push(p0);
subpath.forEach(function (p, i) {
if (i === 0) return;
bbox.grow(p);
if (p0.kind === 'P' && p.kind === 'P') {
path = path.concat(['L', p.x, p.y]);
}
else if (p0.kind === 'P' && p.kind === 'C') {
path = path.concat(['C', p0.x, p0.y, p.in.x, p.in.y, p.x, p.y]);
}
else if (p0.kind === 'C' && p.kind === 'P') {
path = path.concat(['C', p0.out.x, p0.out.y, p.x, p.y, p.x, p.y]);
}
else if (p0.kind === 'C' && p.kind === 'C') {
path = path.concat(['C', p0.out.x, p0.out.y, p.in.x, p.in.y, p.x, p.y]);
}
p0 = p;
});
path.push('z');
return path.join(' ');
}
// Convert an improved path into an SVG string
function formPathCollectionSVG(pathCollection) {
var svg = [];
var bbox = new BBox();
pathCollection.forEach(function (path) {
var d = '';
path.forEach(function (subpath) {
d += formSVGpath(subpath, bbox);
});
svg.push('');
});
svg.push('');
var w = bbox.MX - bbox.mx;
var h = bbox.MY - bbox.my;
var header = '