【修正版】IllustratorからHTML、CSSに書き出すツール

[前回のIllustratorからの書き出しツール](http://qiita.com/onebitious/items/18e402948ef6f64c4aa6)の仕様は、行送り値だけ文字属性から取得し、それをオブジェクトとして段落スタイル名（タグ名）に関連付けていました。
その箇所のソースコードは以下。

```JavaScript:Illustrator2HTML_CSS.jsxから一部抜粋
var myParaStyleObj = {}; //オブジェクト生成
for (var l = 0, myParaLen = myPara.length; l < myParaLen; l++) {
    var myParaStyleName = myPara[l].paragraphStyles[0].name; //段落から段落スタイル名取得
    var myParaLeading = myPara[l].paragraphs[0].leading; //段落から行送り値取得
    myParaStyleObj.myDocParaStyleName = myParaLeading; //ドキュメントのkeyに"オブジェクトの段落スタイル名
    var myLeading = "line-height: " + myRound(myParaStyleObj.myDocParaStyleName, 2) + "px;"; //myParaStyleObj.myDocParaStyleNameに四捨五入関数実行
    myLeadingArray.push(myLeading); //配列に追加
}
```

ですが、こうしてしまうとドキュメント内で使用している順番通りに段落スタイルもソートしていないと、値がテレコになってしまう欠点がありました。

同じタグ名が存在した場合CSSがダブってしまうので、それを回避するのも一つの理由でした。
当時、配列から重複しているものがあったら削除（もしくは1つだけ表示）する方法が分からなかったのです。。。
webではArrayクラスのfilter()で対処できるらしいが、ExtendScript Toolkitではできないようだ。。。

色々調べた結果以下の方法で対処できた。

```JavaScript:overLap.jsx
var sort=[]; //たまに（？）undefinedになるのでグローバルにした
function myOverLap(sort, array) { //重複処理
        var flag;
        sort.push(array[0]);

        for (var i = 0; i < array.length; i++) {
            flag = true;
            for (var j = 0; j < sort.length; j++) {
                if (array[i] === sort[j]) {
                    flag = false;
                }
            }

            if (flag) {
                sort.push(array[i]);
            }
        }
        return sort;
    }
```

[※参考にしたサイト](http://03log.me/blog/2014-08-29-js-array-remove.html)

修正した全体のコードは以下。
エラー処理も追加してみました。

```JavaScript:Illustrator2HTML_CSS.jsx
/*////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
変数定義とエラー処理
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
var myDoc = app.activeDocument; //ドキュメント
var mySel = myDoc.selection; //選択しているテキストフレーム

MAIN: {
    try { //エラー処理
        if (mySel.length == 0 || mySel.constructor.name == "TextRange") {
            alert("テキストフレームを選択してください。");
            break MAIN;
        }
    } catch (e) {
        break MAIN;
    }

    var myPara = myDoc.selection[0].paragraphs; //選択しているフレームの段落スタイル
    var myParaStyle = myDoc.paragraphStyles; //ドキュメントの段落スタイル

    /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       配列定義
       ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
    var myHTMLArray = []; //HTMLタグ用配列
    var myCSSArray = []; //CSS用配列
    var myPropArray = []; //CSSプロパティ用配列
    var mySizeArray = []; //サイズ用配列
    var myFontFamilyArray = []; //フォントファミリー用配列
    var myFontWeightArray = []; //フォントウェイト用配列
    var myColorArray = []; //カラー用配列
    var myLeadingArray = []; //行送り用配列
    var myJustificationArray = []; //行揃え用配列
    var sort = []; //重複処理関数内の配列

    /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       関数定義
       ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
    function zeroPad(myNum) { //ゼロパディング
        var myNum = ('00' + myNum).slice(-2);
        return myNum;
    }

    function myRound(number, n) { //四捨五入
        var myPow = Math.pow(10, n);
        return Math.round(number * myPow) / myPow;
    }

    function myOverLap(sort, array) { //重複処理
        var flag;
        sort.push(array[0]);

        for (var i = 0; i < array.length; i++) {
            flag = true;
            for (var j = 0; j < sort.length; j++) {
                if (array[i] === sort[j]) {
                    flag = false;
                }
            }

            if (flag) {
                sort.push(array[i]);
            }
        }
        return sort;
    }

    /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        Illustrator2HTML
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
    for (var i = 0; i < mySel.length; i++) {
        var myCont = mySel[i].contents; //コンテンツ内容全体

        var myParaLen = mySel[i].paragraphs.length; //段落数を取得
        for (var j = 0; j < myParaLen; j++) {
            var myPraContents = mySel[i].paragraphs[j].contents; //段落ごとのコンテンツを取得

            var myParaName = mySel[i].paragraphs[j].paragraphStyles[0].name; //コンテンツごとの段落スタイル名（タグ名）を取得
            myCSSArray.push(myParaName); //配列に追加

            var myStartTag = "<" + myParaName + ">"; //開始タグ
            var myEndTag = "</" + myParaName + ">"; //終了タグ       
            var myHTMLSentence = myStartTag + myPraContents + myEndTag; //開始タグ＋コンテンツ＋終了タグ
            myHTMLArray.push(myHTMLSentence); //配列に追加

            var myFontSize = myPara[j].size; //サイズ 
            var myFontSize = "font-size: " + myRound(myFontSize, 2) + "px;"; //myFontSizeに四捨五入関数実行
            mySizeArray.push(myFontSize); //配列に追加

            var myFontFamily = myPara[j].textFont.family; //フォントファミリー。※ps名が取得できない 20170102課題
            var myFontFamily = "font-family: " + myFontFamily + ";";
            myFontFamilyArray.push(myFontFamily); //配列に追加

            var myFontWeight = myPara[j].textFont.style; //フォントウェイト
            var myFontWeight = "font-weight: " + myFontWeight + ";";
            myFontWeightArray.push(myFontWeight); //配列に追加

            var myColorRed = myPara[j].fillColor.red.toString(16).toUpperCase(); //red値を取得（大文字のHEX値）
            var myColorRed = zeroPad(myColorRed); //ゼロパディング関数実行
            var myColorGreen = myPara[j].fillColor.green.toString(16).toUpperCase(); //green値を取得（大文字のHEX値）
            var myColorGreen = zeroPad(myColorGreen); //ゼロパディング関数実行
            var myColorBlue = myPara[j].fillColor.blue.toString(16).toUpperCase(); //blue値を取得（大文字のHEX値）
            var myColorBlue = zeroPad(myColorBlue); //ゼロパディング関数実行
            var myColor = "color: #" + myColorRed + myColorGreen + myColorBlue + ";"; //rgb値として取得
            myColorArray.push(myColor); //配列に追加

            var myJustification = myPara[j].justification; //行揃え
            switch (myJustification) {
            case Justification.LEFT:
                myJustification = "text-align: left;";
                break;
            case Justification.CENTER:
                myJustification = "text-align: center;";
                break;
            case Justification.RIGHT:
                myJustification = "text-align: right;";
                break;
            case Justification.FULLJUSTIFYLASTLINELEFT:
                myJustification = "text-align: justify;";
                break;
            }
            myJustificationArray.push(myJustification); //配列に追加

            var myParaLeading = myPara[j].paragraphs[0].leading; //段落から行送り値取得
            var myLeading = "line-height: " + myRound(myParaLeading, 2) + "px;";
            myLeadingArray.push(myLeading); //配列に追加
        }
    }

    for (var m = 0, myCSSArrayLen = myCSSArray.length; m < myCSSArrayLen; m++) {
        var myCSSResult = myCSSArray[m] + "{" + mySizeArray[m] + myFontFamilyArray[m] + myFontWeightArray[m] + myColorArray[m] + myLeadingArray[m] + myJustificationArray[m] + "margin: 0;" + "}"; //CSS生成
        myPropArray.push(myCSSResult); //配列に追加  
    }

    var myHTMLArray = myHTMLArray.toString(); //HTMLタグ用配列を文字列に変換　※変数上書き
    var myHTMLArray = myHTMLArray.replace(/,/g, ""); //文字列化したCSVのカンマを削除
    var myPropArray = myOverLap(sort, myPropArray).toString(); //CSS用配列に重複関数実行し、文字列に変換　※変数上書き
    var myPropArray = myPropArray.replace(/,/g, ""); //文字列化したCSVのカンマを削除

    var MyHTMLRessult = '<!DOCTYPE html><html lang="ja"><head><meta charset="UTF-8"><title>Document</title><style>' + myPropArray + '</style></head><body>' + myHTMLArray + '</body></html>'; //HTML生成

    /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       ファイル保存
       ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
    (function () { //無名関数を定義し実行
        var inputFileName = File.saveDialog("保存先とファイル名を指定して下さい");
        if (inputFileName == null) { //キャンセル処理
            alert("キャンセルしました。");
            return;
        }

        var inputFileName = inputFileName.toString(); //ファイル名に拡張子がないときの処理
        var myNewText = inputFileName.match(/.html/); //拡張子".txt"を付与
        if (myNewText) {
            var inputFileName = inputFileName; //入力したファイル名に拡張子が含まれる場合はそのまま
        } else {
            var inputFileName = inputFileName + ".html"; //入力したファイル名に拡張子が含まれない場合は付与
        }

        var fileObj = new File(inputFileName); //ファイル名を入力して保存
        var inputFileName = fileObj.open("w");
        if (inputFileName == true) {
            fileObj.encoding = "UTF-8"; //UTF-8を指定。これを入れないと異体字依存で書き出されない場合がある。
            fileObj.writeln(MyHTMLRessult); //書き出すテキストを連結
            fileObj.close();
            alert("処理が終わりました。");
        }
    })();
}
```

以下の設定で確認してみました。
![image](https://qiita-image-store.s3.amazonaws.com/0/122812/604f7570-7a35-09ac-5fb9-b29ec0e9036d.png)

```HTML:I_am_a_cat.html
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        h1 {
            font-size: 31.24px;
            font-family: HGS行書体;
            font-weight: ﾒﾃﾞｨｳﾑ;
            color: #00FF00;
            line-height: 54.66px;
            text-align: left;
            margin: 0;
        }
        
        h2 {
            font-size: 21.65px;
            font-family: MS UI Gothic;
            font-weight: 標準;
            color: #22B573;
            line-height: 23.65px;
            text-align: center;
            margin: 0;
        }
        
        h3 {
            font-size: 14.97px;
            font-family: A-OTF UD新ゴコンデ60 Pr6;
            font-weight: EL;
            color: #FF7BAC;
            line-height: 20.37px;
            text-align: justify;
            margin: 0;
        }
        
        p {
            font-size: 11.63px;
            font-family: RoG2サンセリフStd;
            font-weight: B;
            color: #3FA9F5;
            line-height: 20.35px;
            text-align: center;
            margin: 0;
        }
    </style>
</head>

<body>
    <h1>青空文庫：吾輩は猫である　夏目漱石</h1>
    <h2>吾輩は猫である</h2>
    <h3>夏目漱石</h3>
    <p>吾輩は猫である。名前はまだ無い。</p>
    <p>どこで生れたかとんと見当がつかぬ。</p>
    <p>何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。吾輩はここで始めて人間というものを見た。しかもあとで聞くとそれは書生という人間中で一番獰悪な種族であったそうだ。この書生というのは時々我々を捕えて煮て食うという話である。しかしその当時は何という考もなかったから別段恐しいとも思わなかった。ただ彼の掌に載せられてスーと持ち上げられた時何だかフワフワした感じがあったばかりである。掌の上で少し落ちついて書生の顔を見たのがいわゆる人間というものの見始であろう。この時妙なものだと思った感じが今でも残っている。第一毛をもって装飾されべきはずの顔がつるつるしてまるで薬缶だ。その後猫にもだいぶ逢ったがこんな片輪には一度も出会わした事がない。のみならず顔の真中があまりに突起している。そうしてその穴の中から時々ぷうぷうと煙を吹く。どうも咽せぽくて実に弱った。これが人間の飲む煙草というものである事はようやくこの頃知った。</p>
</body>
</html>
```

一応、大丈夫のようだ。。。

※検証はWindows10　Google Chromeでしか行っておりません。