Illustratorのグラデーション設定からCSSプロパティを書き出す。

**仕様**
Illustratorのドキュメント上でグラデーションが設定されたオブジェクトを選択し以下を取得。
・座標
・サイズ
・線形、円形
・角度
・グラデーションスライダーの位置・カラー・数を取得。
上記の設定をHTMLとCSSに書き出す。

**サンプル**
Illustratorのウィンドウ -> スウォッチライブラリ -> グラデーション -> メタル
に既存のグラデーションを設定して試してみます。
![image](https://qiita-image-store.s3.amazonaws.com/0/122812/5900f70b-90d7-9b64-6ea5-951dc617b3b7.png)
▲右下から3番目のもの

![image](https://qiita-image-store.s3.amazonaws.com/0/122812/116a3216-04a5-70c5-c666-d5cecc844515.png)
![image](https://qiita-image-store.s3.amazonaws.com/0/122812/a0963bcb-9932-b9ec-0c99-f89b83a5c68f.png)


種類：線形
角度：-90°
グラデデーションスライダーの設定、左より、
位置：0%　カラー：#F0EEEB(R:240 G:238 B:235)
位置：0%　カラー：#FFECB6(R:255 G:236 B:182)　※0%の位置に2つ設定されています。
位置：10.67%　カラー：#FFFEEC(R:255 G:254 B:236)
位置：24.72%　カラー：#DAA700(R:218 G:167 B:0)
位置：39.89%　カラー：#F5EC4D(R:245 G:236 B:77)
位置：64.61%　カラー：#837C62(R:131 G:124 B:98)
位置：74.16%　カラー：#6D9366(R:109 G:147 B:102)
位置：87.08%　カラー：#005179(R:0 G:81 B:121)
位置：93.82%　カラー：#5A9ED7(R:90 G:158 B:215)
位置：100%　カラー：#C9E0F5(R:201 G:224 B:245)
座標とサイズ　X:39.573px　Y:28.029px　W:116.552px　H:60.987px

![WS002.JPG](https://qiita-image-store.s3.amazonaws.com/0/122812/8df04372-dadc-8fe4-954b-a0c5d5e6e1a4.jpeg)

実行すると上図のようなダイアログが表示されます。
矩形か楕円を選択しないと、選択するまでアラートが表示されるようにしました。
ここで言う形状とはグラデーションの種類ではなく、オブジェクトとして作成する形状になります。
理想としては、ドキュメント上のオブジェクトの形状を自動判定して、作成するようにしたかったのですが、Illustrator上で作成されたオブジェクトからは取得できないということが分かりました。

Kanamura様 助言ありがとうございました。

ですので形状はここで選択するようにしました。
※角丸長方形、多角形、スターは対象外。
[先日の投稿を参照](http://qiita.com/onebitious/items/991efb4db087994d48f2)

![image](https://qiita-image-store.s3.amazonaws.com/0/122812/86c860be-9ca4-cec3-01bb-c76d13d907a6.png)
ひとまず上図の設定でOKを押下。
保存先を聞かれるので任意保存。

![キャプチャ.JPG](https://qiita-image-store.s3.amazonaws.com/0/122812/e330486b-2c5c-2b5d-c56c-e63f790f5e26.jpeg)
▲Chromeで表示。

![image](https://qiita-image-store.s3.amazonaws.com/0/122812/7448c16a-8a4b-55fa-5ad8-19667d9bb200.png)
▲右下のCSSを拡大。一応同設定で書き出されています。

書き出されたHTMLは以下。

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

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        
        ._square {
            position: absolute;
            left: 39.573px;
            top: 28.029px;
            width: 116.552px;
            height: 60.987px;
            background: -webkit-linear-gradient(-90deg, #F0EEEB 0%, #FFECB6 0%, #FFFEEC 10.2%, #DAA700 24.72%, #F5EC4D 39.89%, #837C62 64.61%, #6D9366 74.16%, #005179 87.08%, #5A9ED7 93.82%, #C9E0F5 100%);
        }
    </style>
</head>

<body>
    <div class="_square"></div>
</body>

</html>
```

JavaScriptソースコードは以下。

```javascript:frameProp2gradientProp.jsx
/*windows 10
Illustrator CC 2017(21.0.2)
Chrome 56.0.2924.87
Firefox 51.0.1
Opera 43.0.2442.1144
Microsoft Edge 38.14393.0.0
Internet Explorer 11.576.14393.0　→ ×
*/

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

var graStoArr = []; //配列を作成

MAIN: { //ラベル
    //▼選択している文字を取得
    try {
        if (sel[0].constructor.name != "PathItem") {
            alert("グラデーションのシェイプを1つ選択してください。");
            break MAIN; //ここがうまくいかない
        }
    } catch (e) {
        alert("グラデーションのシェイプを1つ選択してください。");
        break MAIN;
    }
    var posiX = round(sel[0].position[0], 3); //X座標
    var minus = -1; //マイナス
    var posiY = round(sel[0].position[1] * minus, 3); //Y座標　負の値になるので-1を乗算
    var wid = round(sel[0].width, 3); //幅
    var hei = round(sel[0].height, 3); //高さ

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

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

    function getColor(_color) { //取得した色値をHEX値、大文字、ゼロパディング
        var _color = zeroPad(_color.toString(16).toUpperCase());
        return _color;
    }
    /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
           ダイアログ表示とタグ、セレクタ取得
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
    //▼入力ダイアログ表示
    var tagFlag = false; //フラグの初期化
    var textFlag = true;
    while (tagFlag == false) { //タグが未選択の場合繰り返す
        var myWin = new Window('dialog', '諸設定', [800, 500, 1025, 730]);
        myWin.elementText = myWin.add("statictext", [10, 10, 450, 30], "矩形か楕円か選択してください。"); //固定テキスト
        myWin.squBtn = myWin.add("radiobutton", [10, 35, 85, 65], "矩形");
        myWin.ovalBtn = myWin.add("radiobutton", [105, 35, 205, 65], "楕円");
        myWin.attriTxt = myWin.add("statictext", [10, 70, 275, 100], "属性名を選択してください。"); //固定テキスト
        myWin.dropdownList = myWin.add("dropdownlist", [10, 100, 200, 120], ["id セレクタ", "class セレクタ", ""]);
        myWin.dropdownList.selection = 0; //デフォルト表示は一番上のもの
        myWin.attriValTxt = myWin.add("statictext", [10, 150, 275, 170], "属性値を入力してください。"); //固定テキスト
        myWin.editText = myWin.add("edittext", [10, 170, 200, 190], "", {
            readonly: false
        }); //id、classセレクタだったら入力できる
        myWin.dropdownList.onChange = function () {
            if (myWin.dropdownList.selection == 2) {
                myWin.editText = myWin.add("edittext", [10, 170, 200, 190], "※属性名空欄時は入力不可", {
                    readonly: true
                }); //入力できなくする
                textFlag = false; //フラグ
            } else {
                myWin.editText = myWin.add("edittext", [10, 170, 200, 190], "", {
                    readonly: false
                }); //id、classセレクタだったら入力できる
            }
        }

        myWin.okBtn = myWin.add("button", [20, 200, 100, 220], "OK", {
            name: "ok"
        });
        myWin.cancelBottom = myWin.add("button", [120, 200, 200, 220], "キャンセル", {
            name: "cancel"
        });

        var bottomFlag = myWin.show(); //ダイアログを表示し、OK、キャンセルボタンの結果を取得

        if (bottomFlag == 2) { //キャンセルの場合処理を抜ける
            alert("キャンセルしました。");
            break MAIN;
        }
        var squBtnResult = myWin.squBtn.value; //矩形ボタン押下時true
        var obalBtnResult = myWin.ovalBtn.value; //楕円ボタン押下時true
        var dropDownListResult = myWin.dropdownList.selection.text; //ドロップダウンリストから選択したセレクタ名が返る

        var mySelName = myWin.editText.text; //入力したテキストが返る

        /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
               タグ、セレクタの設定
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
        //▼セレクタ名の設定
        if (textFlag == false) {
            var selNameResult = "";
        } else if (mySelName == "") {
            var selNameResult = '="○○○○●"';
            var mySelName = '○○○○●';
        } else {
            var selNameResult = '="' + mySelName + '"';
        }

        //▼セレクタの設定
        if (dropDownListResult == "id セレクタ") {
            var selResult = "id";
            var chiceSelector = "#" + mySelName;
        } else if (dropDownListResult == "class セレクタ") {
            var selResult = "class";
            var chiceSelector = "." + mySelName;
        } else {
            var selResult = "";
        }

        //▼タグの設定
        if (squBtnResult == true) {
            var tag = "<div" + " " + selResult + selNameResult + "></div>";
            var CSSgraType = "";
            var tagFlag = true; //フラグ
        } else if (obalBtnResult == true) {
            var tag = "<div" + " " + selResult + selNameResult + "></div>";
            var CSSgraType = "border-radius:" + wid / 2 + "px /" + hei / 2 + "px;";
            var tagFlag = true; //フラグ
        } else if (squBtnResult == false && obalBtnResult == false) {
            alert("形状が選択されていません。");
            var tagFlag = false; //フラグ
        }
    }

    /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
           グラデーション取得
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
    var graStoRedArr = []; //red配列
    var graStoGreenArr = []; //green配列
    var graStoBlueArr = []; //blue配列

    if (sel[0].fillColor.typename == "GradientColor") {
        var graSto = sel[0].fillColor.gradient.gradientStops; //グラデーションポイント
        var graDeg = round((sel[0].fillColor.angle), 1); //角度
        for (var i = 0, graStoLen = graSto.length; i < graStoLen; i++) {
            var graStoRed = graSto[i].color.red;
            var graStoGreen = graSto[i].color.green;
            var graStoBlue = graSto[i].color.blue;
            graStoRedArr.push(graStoRed);
            graStoGreenArr.push(graStoGreen);
            graStoBlueArr.push(graStoBlue);
            var graStoRedResult = getColor(graStoRedArr[i]); //red
            var graStoGreenResult = getColor(graStoGreenArr[i]); //green
            var graStoBlueResult = getColor(graStoBlueArr[i]); //blue
            var graStoColResult = "#" + graStoRedResult + graStoGreenResult + graStoBlueResult;//カラーHEX値
            var myRampPoint = round((graSto[i].rampPoint), 2); //グラデーションスライダー
            var popGraResult = graStoColResult + " " + myRampPoint + "%";
            graStoArr.push(popGraResult);
        }
        var graType = sel[0].fillColor.gradient.type; //種類
        if (graType == GradientType.LINEAR) {
            var graType = "linear";
            var fillResult = "background: -webkit-" + graType + "-gradient(" + graDeg + "deg," + graStoArr + ");"; //ベンダープレフィックス付けないとグラデーションが反転する
        } else {
            var graType = "radial";
            var fillResult = "background: -webkit-" + graType + "-gradient(circle closest-side," + graStoArr + ");";
        }
    }

    //▼CSSに書き出す
    if (textFlag == false) {
        //▼セレクタがない場合
        var selResult = 'div' + '{position:absolute;left:' + posiX + 'px;top:' + posiY + 'px;width:' + wid + 'px;height:' + hei + 'px;' + fillResult + CSSgraType + '}';
    } else {
        //▼セレクタがある場合       
        var selResult = chiceSelector + '{position:absolute;left:' + posiX + 'px;top:' + posiY + 'px;width:' + wid + 'px;height:' + hei + 'px;' + fillResult + CSSgraType + '}';
    }

    var htmlTag = '<!DOCTYPE html><html lang="ja"><head><meta charset="UTF-8"><title>Document</title><style>*{margin:0;padding:0;}' + selResult + '</style></head><body>' + tag + '</body></html>';

    /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       ファイル保存
       ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
    (function saveFile() { //即時関数
        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(htmlTag); //書き出すテキストを連結
            fileObj.close();
            alert("処理が終わりました。");
        }
    }());
}
```


矩形や楕円を作成とはいってもdiv要素にサイズや座標の指定をして着色しているだけなので、オブジェクトを配置しているかと問われると微妙は感じがする。。。
canvas要素にjavascriptで描画すればいいのですが、複雑になるので今回の仕様にしました。
ベンダープレフィックスは -webkit- しか付与していませんが、以下のブラウザで正しく表示されました。
Chrome 56.0.2924.87
Firefox 51.0.1
Opera 43.0.2442.1144
Microsoft Edge 38.14393.0.0
※Internet Explorer 11.576.14393.0はダメでした。
ちなみにChromeでは -webkit- がないとグラデーションが鏡像になります。

ちなみに円形グラデーションにも対応してありますが、縦横比の細かい指定ができないのと、closest-sideなど、どのサイズでもIllustratorと近い形にはなりません。
おまけにradial-gradientでは角度が含めません。
![image](https://qiita-image-store.s3.amazonaws.com/0/122812/8db53043-88ab-bbe0-3881-9d21c4642bc4.png)
▲Illustrator

![image](https://qiita-image-store.s3.amazonaws.com/0/122812/ae674630-fabf-7e19-fbb1-faae666e5384.png)
▲Chrome

動作確認は上記のブラウザと windows 10、Illustrator CC 2017(21.0.2)のみでしか行っておりません。