自分だけで持ってても使いどころがないので蔵出し。
- 適当なオブジェクトを選択してスクリプト実行、保存ダイアログに「xxx.svg」とつけて保存してください。
- 線、四角形、楕円、多角形しか書き出しません。
- 文字はアウトラインを取ってください。
SVG書き出し.jsx
(function(){
if(app.documents.length){
main(app.activeDocument);
}
}());
function main(doc){
if(!doc.selection.length){ return; };
doc.viewPreferences.properties={
horizontalMeasurementUnits:MeasurementUnits.POINTS,
verticalMeasurementUnits:MeasurementUnits.POINTS,
strokeMeasurementUnits:MeasurementUnits.POINTS,
};
var objs = doc.selection;
var pos = getVisiblePosition(objs);
var svgTxtAry = [];
svgTxtAry.push('<?xml version="1.0" encoding="utf-8"?>');
svgTxtAry.push('<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">');
svgTxtAry.push(
'<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"'
+' x="0pt" y="0pt" width="'+round1000(pos.w)+'pt" height="'+round1000(pos.h)+'pt"'
+' viewBox="0 0 '+round1000(pos.w)+' '+round1000(pos.h)+'">'
);
for(var i=0,len=objs.length;i<len;i++){
var obj = objs[i];
//$.writeln(obj.constructor.name);
switch(obj.constructor.name){
case 'GraphicLine':
case 'Oval':
case 'Rectangle':
case 'Polygon':
svgTxtAry.push(getSvgPath(obj,pos));
break;
default:
break;
}
}
svgTxtAry.push('</svg>');
//$.writeln(svgTxtAry.join('\n'));
var svgFile = File.saveDialog('SVGを保存');
if(svgFile){
svgFile.encoding = 'UTF8';
svgFile.lineFeed = 'Unix';
if(svgFile.open('w')){
svgFile.write(svgTxtAry.join('\n'));
svgFile.close();
}else{
alert('SVGを保存できません');
}
}
}
function getVisiblePosition(objs){
var bns = objs[0].visibleBounds.slice();
for(var i=1,len=objs.length;i<len;i++){
var _bns = objs[i].visibleBounds;
bns[0]=Math.min(bns[0],_bns[0]);
bns[1]=Math.min(bns[1],_bns[1]);
bns[2]=Math.max(bns[2],_bns[2]);
bns[3]=Math.max(bns[3],_bns[3]);
}
return {x:bns[1],y:bns[0],w:bns[3]-bns[1],h:bns[2]-bns[0]};
}
function getSvgPath(obj,pos){
var paths = obj.paths;
var pathAry = [];
for(var i=0,len=paths.length;i<len;i++){
var path = paths[i];
var roundPath = normalizePath(path.entirePath,[pos.x,pos.y],true);
var svgPath = pathToSvgPath(
roundPath,(path.pathType===PathType.OPEN_PATH)
);
pathAry.push(svgPath);
}
return '<path fill="'+ getSvgColor(obj.fillColor)+'"'
+' stroke="'+ getSvgColor(obj.strokeColor)+'"'
+' stroke-width="'+ obj.strokeWeight+'"'
+' d="'+pathAry.join(' ')+'"'+getLineCapAndjoin(obj)+' />';
}
function getSvgColor(color){
switch(color.name){
case 'None':return 'none';
case 'Black':return '#000000';
case 'Paper':return '#FFFFFF';
default: break;
}
var colorValue;
if(color.space==ColorSpace.RGB){
colorValue = color.colorValue;
}else{
var tmpColor = color.duplicate();
tmpColor.space = ColorSpace.RGB;
colorValue = tmpColor.colorValue;
tmpColor.remove();
}
return '#'+toHex(colorValue[0])+toHex(colorValue[1])+toHex(colorValue[2]);
};
function getLineCapAndjoin(obj){
var ary = [];
var strokeLinecap,strokeLinejoin,strokeDasharray;
if(obj.strokeWeight){
//線の先
switch(obj.endCap){
case EndCap.ROUND_END_CAP:
strokeLinecap="round";break;
case EndCap.PROJECTING_END_CAP:
strokeLinecap="square";break;
case EndCap.BUTT_END_CAP:
strokeLinecap="butt";break;
default:break;
};
if(strokeLinecap){
ary.push('stroke-linecap="'+strokeLinecap+'"');
}
//線の角
switch(obj.endJoin){
case EndJoin.ROUND_END_JOIN:
strokeLinejoin="round";break;
case EndJoin.BEVEL_END_JOIN:
strokeLinejoin="bevel";break;
case EndJoin.MITER_END_JOIN:
strokeLinejoin="miter";break;
default:break;
};
if(strokeLinejoin){
ary.push('stroke-linejoin="'+strokeLinejoin+'"');
};
try{
strokeDasharray = obj.strokeDashAndGap;
}catch(e){};
if(strokeDasharray){
ary.push('stroke-dasharray="'+strokeDasharray.join(',')+'"');
};
}
return ary.length? ' '+ary.join(' '):'';
}
function toHex(N) {
if (N==null) return "00";
N=parseInt(N); if (N==0 || isNaN(N)) return "00";
N=Math.max(0,N); N=Math.min(N,255); N=Math.round(N);
return "0123456789ABCDEF".charAt((N-N%16)/16)
+ "0123456789ABCDEF".charAt(N%16);
};
function pathToSvgPath(entirePath,pathOpen){
var pathAry = [];
var command = 'L';//デフォルトはL
var startPoint,endPoint;
for(var p=0,max=(pathOpen?entirePath.length-1:entirePath.length);p<max;p++){
startPoint = null, endPoint = null;
startPoint = entirePath[p];
if(startPoint.length==2) startPoint = [startPoint,startPoint,startPoint];
endPoint = entirePath[p+1]||entirePath[0];
if(endPoint.length==2) endPoint = [endPoint,endPoint,endPoint];
pathAry.push(startPoint[1].join(','));//支点
if(startPoint[1][0]==startPoint[2][0] && startPoint[1][1]==startPoint[2][1]
&& endPoint[0][0]==endPoint[1][0] && endPoint[0][1]==endPoint[1][1]){
if(command!=='L'){ pathAry.push('L');command = 'L'; };
}else{
if(command!=='C'){ pathAry.push('C');command = 'C'; };
pathAry.push(startPoint[2].join(','));
pathAry.push(endPoint[0].join(','));
}
}
pathAry.push(endPoint[1].join(','));
if(!pathOpen){ pathAry.push('z'); };
pathAry.unshift('M');
return pathAry.join(' ');
};
function normalizePath(pathPoints,zeroPoint){
//オブジェクトの0位置から計算したパスを書き出す。
if(!zeroPoint) zeroPoint = [0,0];
var i = pathPoints.length;
var _pathPoints = new Array(i);
while(i--){
var pathPoint = pathPoints[i];
if(typeof pathPoint[0]=='number'){
_pathPoints[i] = [
round1000(pathPoint[0]-zeroPoint[0]),
round1000(pathPoint[1]-zeroPoint[1])
];
}else{
_pathPoints[i] = normalizePath(pathPoint,zeroPoint);
}
};
return _pathPoints;
};
function round1000(n){
return Math.round(n*1000)/1000;
};