LoginSignup
3
3

More than 5 years have passed since last update.

InDesignで、選択範囲をSVG書き出しするスクリプト

Last updated at Posted at 2015-10-01

自分だけで持ってても使いどころがないので蔵出し。

  • 適当なオブジェクトを選択してスクリプト実行、保存ダイアログに「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;
};

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3