getGradientInfo.jsx

/**********************************************************

getGradientInfo.jsx
選択したオブジェクトのグラデーション情報を取得し、
アクティブドキュメントのフォルダに CSV 形式で保存するスクリプト。
既存の `gradientName` をチェックし、連番 (`gradientName_01`, `gradientName_02`...) を付与する。

**********************************************************/

#target illustrator

if (app.documents.length > 0) {
    var doc = app.activeDocument;
    var selection = doc.selection;

    if (doc.fullName) {
        var docPath = doc.fullName.parent.fsName; // ドキュメントのフォルダ取得
        var csvFile = new File(docPath + "/gradientInfo.csv");
        var csvData = [];
        var existingGradientNames = getExistingGradientNames(csvFile); // 既存のグラデーション名を取得
        var nextGradientIndex = getNextGradientIndex(existingGradientNames); // 次のグラデーション番号を決定

        // ヘッダーを追加(ファイルが存在しない場合のみ)
        if (!csvFile.exists) {
            csvData.push("gradientName,rampPoint,midPoint,opacity,color");
        }

        if (selection.length > 0) {
            for (var i = 0; i < selection.length; i++) {
                var obj = selection[i];

                if (obj.filled && obj.fillColor.typename === "GradientColor") {
                    var gradient = obj.fillColor.gradient;

                    // ** 既存の `gradientName` を確認し、新規追加分の名前を決定 **
                    var gradientName = "gradientName_" + padNumber(nextGradientIndex);
                    nextGradientIndex++; // 次の番号に更新

                    for (var j = 0; j < gradient.gradientStops.length; j++) {
                        var stop = gradient.gradientStops[j];

                        var rampPoint = Math.round(stop.rampPoint);
                        var midPoint = Math.round(stop.midPoint);
                        var opacity = Math.round(stop.opacity);

                        var red = !isNaN(stop.color.red) ? Math.round(stop.color.red) : 0;
                        var green = !isNaN(stop.color.green) ? Math.round(stop.color.green) : 0;
                        var blue = !isNaN(stop.color.blue) ? Math.round(stop.color.blue) : 0;
                        var hexColor = rgbToHex(red, green, blue);

                        csvData.push(
                            gradientName + "," +
                            rampPoint + "," +
                            midPoint + "," +
                            opacity + "," +
                            hexColor
                        );
                    }
                }
            }

            if (csvData.length > 1) {
                // CSVファイルを開いてデータを書き込む
                csvFile.encoding = "UTF-8";
                csvFile.open("a"); // 追記モード
                csvFile.writeln(csvData.join("\n"));
                csvFile.close();

                alert("グラデーション情報を CSV ファイルに保存しました。\n" + csvFile.fsName);
            } else {
                alert("選択オブジェクトにグラデーションが適用されていません。");
            }
        } else {
            alert("オブジェクトが選択されていません。");
        }
    } else {
        alert("このドキュメントは保存されていません。先に保存してください。");
    }
} else {
    alert("ドキュメントを開いてください。");
}

/**********************************************************

 既存の `gradientName` を取得する関数

**********************************************************/
function getExistingGradientNames(csvFile) {
    var names = [];

    if (csvFile.exists) {
        csvFile.open("r");
        var lines = csvFile.read().split("\n");
        csvFile.close();

        for (var i = 1; i < lines.length; i++) { // 1行目(ヘッダー)はスキップ
            var values = lines[i].split(",");
            if (values.length > 0) {
                var name = trimString(values[0]);
                if (name.indexOf("gradientName_") === 0) { // `startsWith()` の代わり
                    names.push(name);
                }
            }
        }
    }

    return names;
}

/**********************************************************

 次の `gradientName` の番号を決定する関数

**********************************************************/
function getNextGradientIndex(existingNames) {
    var maxIndex = 0;

    for (var i = 0; i < existingNames.length; i++) {
        var nameParts = existingNames[i].split("_");
        var index = parseInt(nameParts[nameParts.length - 1], 10);
        if (!isNaN(index) && index > maxIndex) {
            maxIndex = index;
        }
    }

    return maxIndex + 1;
}

/**********************************************************

 数字を2桁にパディングする関数(例: 1 → "01", 12 → "12")

**********************************************************/
function padNumber(num) {
    return num < 10 ? "0" + num : num.toString();
}

/**********************************************************

 文字列の前後の空白を削除する関数

**********************************************************/
function trimString(str) {
    return str.replace(/^\s+|\s+$/g, "");
}

/**********************************************************

 RGB を Hex コードに変換する関数

**********************************************************/
function rgbToHex(r, g, b) {
    return "#" + toHex(r) + toHex(g) + toHex(b);
}

function toHex(value) {
    var hex = Math.round(value).toString(16);
    return hex.length === 1 ? "0" + hex : hex;
}

setGradientInfo.jsx

/**********************************************************

setGradientInfo.jsx
CSVファイルを読み込み、Illustratorのスウォッチに複数のグラデーションを一括登録するスクリプト。
ストップの順序と `rampPoint` のズレを防ぎ、適切に適用するように修正。

**********************************************************/

#target illustrator

if (app.documents.length > 0) {
    var doc = app.activeDocument;

    if (doc.fullName) {
        var docPath = doc.fullName.parent.fsName;
        var csvFile = new File(docPath + "/gradientInfo.csv");

        if (csvFile.exists) {
            csvFile.open("r");
            var csvContent = csvFile.read();
            csvFile.close();

            var gradientsData = parseCSV(csvContent);

            if (gradientsData.length === 0) {
                alert("CSV に有効なグラデーションデータがありません。");
                exit();
            }

            // ** グラデーションごとに処理 **
            for (var g = 0; g < gradientsData.length; g++) {
                var gradientInfo = gradientsData[g];

                // ** `rampPoint` の昇順ソート(重要)**
                gradientInfo.stops.sort(function(a, b) {
                    return a.rampPoint - b.rampPoint;
                });

                // ** グラデーション作成(名前設定なし)**
                var newGradient = createGradient();

                // ** ストップ数をチェックし、足りない場合は追加 **
                while (newGradient.gradientStops.length < gradientInfo.stops.length) {
                    newGradient.gradientStops.add();
                }

                // ** ストップを適用(順番を保つ)**
                for (var i = 0; i < gradientInfo.stops.length; i++) {
                    var stop = newGradient.gradientStops[i];
                    var stopData = gradientInfo.stops[i];

                    stop.rampPoint = stopData.rampPoint;
                    stop.midPoint = stopData.midPoint;
                    stop.opacity = stopData.opacity;

                    var colorRGB = hexToRGB(stopData.color);
                    var newColor = new RGBColor();
                    newColor.red = colorRGB.red;
                    newColor.green = colorRGB.green;
                    newColor.blue = colorRGB.blue;

                    stop.color = newColor;
                }
            }

            alert("すべてのグラデーションがスウォッチに追加されました!");
        } else {
            alert("gradientInfo.csv が見つかりません。\n先に getGradientInfo.jsx を実行してください。");
            exit();
        }
    } else {
        alert("このドキュメントは保存されていません。先に保存してください。");
        exit();
    }
} else {
    alert("ドキュメントを開いてください。");
    exit();
}

/**********************************************************

 グラデーションを作成する関数(名前は設定しない)

**********************************************************/
function createGradient() {
    var theGradient = app.activeDocument.gradients.add();
    theGradient.type = GradientType.LINEAR; // リニアグラデーション
    return theGradient;
}

/**********************************************************

 CSVをパースして複数のグラデーションを処理する関数

**********************************************************/
function parseCSV(csvString) {
    var lines = csvString.split("\n");
    var gradients = {};
    var gradientList = [];

    for (var i = 1; i < lines.length; i++) {
        var values = lines[i].split(",");
        if (values.length === 5) {
            var gName = trimString(values[0]);
            var stopData = {
                rampPoint: parseFloat(values[1]),
                midPoint: parseFloat(values[2]),
                opacity: parseFloat(values[3]),
                color: trimString(values[4])
            };

            if (!gradients[gName]) {
                gradients[gName] = { name: gName, stops: [] };
                gradientList.push(gradients[gName]);
            }
            gradients[gName].stops.push(stopData);
        }
    }

    return gradientList;
}

/**********************************************************

 文字列の前後の空白を削除する関数

**********************************************************/
function trimString(str) {
    return str.replace(/^\s+|\s+$/g, "");
}

/**********************************************************

 Hexカラーコードを RGB に変換する関数

**********************************************************/
function hexToRGB(hex) {
    hex = hex.replace("#", "");
    return {
        red: parseInt(hex.substring(0, 2), 16),
        green: parseInt(hex.substring(2, 4), 16),
        blue: parseInt(hex.substring(4, 6), 16)
    };
}

CSVフォーマット

gradientInfo.csv

gradientName,rampPoint,midPoint,opacity,color
gradientName_01,0,50,100,#d457c3
gradientName_01,20,50,100,#6ee089
gradientName_01,40,50,100,#99ff2a
gradientName_01,70,50,100,#ff5d15
gradientName_01,100,50,100,#f33fff
gradientName_02,0,50,100,#ffff00
gradientName_02,100,50,100,#000000
gradientName_03,0,50,100,#ff0000
gradientName_03,100,50,100,#0000ff