一个UI工具脚本,换来一个月的下午茶

1,691 阅读14分钟

原因

最近接到一个设计师需求,说她做的Adobe Illustrator(AI)设计稿,做了一个版本之后,需要做多国语言的支持,目前的做法是复制出来,再里面挨个挨个修改文字或字体颜色。

缺点:

  • 工作量大
  • 容易写错写漏。

希望有一个插件或工具可以自动实现。

找方案

于是上网问了下gpt,说可以使用脚本或插件实现。意外的发现这个网站。 redokun.com/blog/illust…

image.png

上面很好的实现了如何通过当前ai文件导出国际化配置,再通过编辑导入回ai

具体逻辑:

  1. 下载对应的脚本文件,解压。
  2. 复制到Applications/Adobelllustrator[版本]/Presets/en_US/Scripts 这个路径

image.png

  1. 重启ai工具
  2. 点击菜单-> 文件 -》 脚本 -》 选择 redokun_export-text.jsx
  3. 修改导出的json文件,替换希望修改的国际化内容
  4. 点击菜单-> 文件 -》 脚本 -》 选择 redokun_import-text.jsx

缺点

只支持修改文本,如何要修改字体和别的属性就无法做到了。

自定义脚本

突然看到脚本的后觉是jsx跟前端后缀是一致的,于是使用vscode打开看看,果然是js。(我都开始怀疑adobe的工具是用js开发的) 那真的完美的给了前端的一个开发机会。下面是打开后的源码

image.png

image.png

可以看到为何保护源码,作者已经混淆了代码,只能自己实现了。

通过gpt一番折腾实现了

  • 单个文件的导入导出

  • 批量多个文件的导入导出

    注意点:工具js的内核比较旧,连JSON和Array这些基本库都没有,只能自己实现。

单条配置

导出

Sep-27-2024 18-54-10.gif 导入

Sep-27-2024 19-07-13.gif 在原有作者的思路进行扩展,新增了下面更新

  • content: 代表文本内容
  • font:使用的字体库
  • size:字体大小
  • fillColor:填充的颜色

下面是导出的json格式

[
  {
    "id": 0,
    "content": "内容:vue响应式",
    "font": "AdobeSongStd-Light",
    "size": 56.4122505187988,
    "fillColor": "#000000"
  },
  {
    "id": 1,
    "content": "标题:前端开发",
    "font": "AdobeSongStd-Light",
    "size": 56.4121856689453,
    "fillColor": "#000000"
  }
]

完整的操作流程

  1. 安装复制script文件夹下面的单条导出文本配置.jsx,单条导入文本配置.jsx 到Mac电脑这里/Applications/Adobe/Illustrator 2022/Presets.localized/zh_CN/脚本/ (mac系统+M1芯+2022版本)
  2. 重启ai软件
  3. 打开一个ai文件
  4. 点击菜单-> 文件 -》 脚本 -》 选择 单条导出文本配置.jsx
  5. 此时会在桌面 /Users/xxxxx用户名/Desktop/ai单条文本配置.json
  6. 使用记事本或vscode 编辑 ai单条文本配置.json 如:
[
  {
    "id": 0,
    "content": "内容:vue响应式",
    "font": "AdobeSongStd-Light",
    "size": 56.4122505187988,
    "fillColor": "#000000"
  },
  {
    "id": 1,
    "content": "标题:前端开发",
    "font": "AdobeSongStd-Light",
    "size": 56.4121856689453,
    "fillColor": "#000000"
  }
]

  1. 修改json配置
  • content代表文本内容
  • font:使用的字体库
  • size:字体大小
  • fillColor:填充的颜色

修改如下

  • 我们把内容改成英文,同时修改字体颜色为红色

[
  {
    "id": 0,
    "content": "content:vue respone",
    "font": "AdobeSongStd-Light",
    "size": 56.4122505187988,
    "fillColor": "#d1242f"
  },
  {
    "id": 1,
    "content": "title:front-dev",
    "font": "AdobeSongStd-Light",
    "size": 56.4121856689453,
    "fillColor": "#d1242f"
  }
]
  1. 点击菜单-> 文件 -》 脚本 -》 选择 单条导入文本配置.jsx
  2. 选择刚刚编辑的 /Users/xxxxx用户名/Desktop/ai单条文本配置.json 这个文件
  3. 此时提示更新成功,当前文档会根据配置自动更新设置信息

批量配置

导出

Sep-27-2024 19-19-171111.gif 导入

Sep-27-2024 19-18-322222.gif

在单条的基础上,添加了选择语言的支持。导出时候的格式如下


[
  {
    "language": "Chinese",
    "text_list": [
      {
        "id": 0,
        "content": "内容:vue响应式",
        "font": "AdobeSongStd-Light",
        "size": 56.4122505187988,
        "fillColor": "#000000"
      },
      {
        "id": 1,
        "content": "标题:前端开发",
        "font": "AdobeSongStd-Light",
        "size": 56.4121894836426,
        "fillColor": "#000000"
      }
    ]
  },
  {
    "language": "English",
    "text_list": [
      {
        "id": 0,
        "content": "内容:vue响应式",
        "font": "AdobeSongStd-Light",
        "size": 56.4122505187988,
        "fillColor": "#000000"
      },
      {
        "id": 1,
        "content": "标题:前端开发",
        "font": "AdobeSongStd-Light",
        "size": 56.4121894836426,
        "fillColor": "#000000"
      }
    ]
  }
]

你需要在不同的配置里面修改对应的属性,并且在导入的时候除了要选择json文件,还要多选一个导出的文件夹。这个文件夹会根据配置生成对应的不同ai文件如:

  • Chinese.ai
  • English.ai

完成的操作流程

  1. 安装复制script文件夹下面的批量导出文本配置.jsx,批量导入文本配置.jsx 到Mac电脑这里/Applications/Adobe/Illustrator 2022/Presets.localized/zh_CN/脚本/ (mac系统+M1芯+2022版本)
  2. 重启ai软件
  3. 打开一个ai文件
  4. 点击菜单-> 文件 -》 脚本 -》 选择 批量导出文本配置.jsx
  5. 此时提示选择的语言,我们选择Chinese和English(中文和英文)
  6. 此时会在桌面 /Users/xxxxx用户名/Desktop/ai批量文本配置.json
  7. 使用记事本或vscode编辑 ai批量文本配置.json文件 如:
[
  {
    "language": "Chinese",
    "text_list": [
      {
        "id": 0,
        "content": "内容:vue响应式",
        "font": "AdobeSongStd-Light",
        "size": 56.4122505187988,
        "fillColor": "#000000"
      },
      {
        "id": 1,
        "content": "标题:前端开发",
        "font": "AdobeSongStd-Light",
        "size": 56.4121894836426,
        "fillColor": "#000000"
      }
    ]
  },
  {
    "language": "English",
    "text_list": [
      {
        "id": 0,
        "content": "内容:vue响应式",
        "font": "AdobeSongStd-Light",
        "size": 56.4122505187988,
        "fillColor": "#000000"
      },
      {
        "id": 1,
        "content": "标题:前端开发",
        "font": "AdobeSongStd-Light",
        "size": 56.4121894836426,
        "fillColor": "#000000"
      }
    ]
  }
]
  1. 修改json配置
  • language:代表当前操作的语言
  • content:文本内容
  • font:使用的字体库
  • size:字体大小
  • fillColor:填充的颜色

修改如下

  • 我们把内容改成英文,同时修改字体颜色为红色
[
  {
    "language": "Chinese",
    "text_list": [
      {
        "id": 0,
        "content": "内容:vue响应式2",
        "font": "AdobeSongStd-Light",
        "size": 56.4122505187988,
        "fillColor": "#d1242f"
      },
      {
        "id": 1,
        "content": "标题:前端开发2",
        "font": "AdobeSongStd-Light",
        "size": 56.4121894836426,
        "fillColor": "#d1242f"
      }
    ]
  },
  {
    "language": "English",
    "text_list": [
      {
        "id": 0,
        "content": "content:vue respone",
        "font": "AdobeSongStd-Light",
        "size": 56.4122505187988,
        "fillColor": "#d1242f"
      },
      {
        "id": 1,
        "content": "title:front-dev",
        "font": "AdobeSongStd-Light",
        "size": 56.4121894836426,
        "fillColor": "#d1242f"
      }
    ]
  }
]

 
  1. 点击菜单-> 文件 -》 脚本 -》 选择 批量导入文本配置.jsx
  2. 选择刚刚编辑的 /Users/xxxxx用户名/Desktop/ai批量文本配置.json 这个文件
  3. 然后会提示需要导出的文件夹地址:我们选择 /Users/xxxxx用户名/Desktop/
  4. 此时提示成功,当前文档会根据配置自动更新设置信息,同时/Users/jason.yang/Documents/ 会新增多两个文件
  • Chinese.ai
  • English.ai

相关源码

单条

单条导出文本配置.jsx

// 获取当前文档中的所有文本框


if (app.documents.length > 0) { 
    var doc = app.activeDocument;
    var textItems = doc.textFrames;
    var textData = [];

    // 遍历所有文本框,并将文本内容与样式存储为对象
    for (var i = 0; i < textItems.length; i++) {
        var textFrame = textItems[i];
        var fillColor = textFrame.textRange.characterAttributes.fillColor;

        // 将 RGBColor 转换为 HEX 格式
        var hexColor = rgbToHex(fillColor.red, fillColor.green, fillColor.blue);
        
        var textObject = {
            id: i,
            content: textFrame.contents,
            font: textFrame.textRange.characterAttributes.textFont.name,
            size: textFrame.textRange.characterAttributes.size,
            fillColor: hexColor // 使用 HEX 颜色
        };
        textData.push(textObject);
    }

    // 使用手动实现的 stringify 替代 JSON.stringify
    var jsonString = stringify(textData);

    // 保存 JSON 文件到桌面,并设置为 UTF-8 编码
    var file = new File(Folder.desktop + "/ai单条文本配置.json");
    file.encoding = "UTF-8";  // 设置文件编码为 UTF-8
    file.open("w");
    file.write(jsonString);
    file.close();

    // 提示用户文件已导出
    alert("文件已经导出到: " + file.fsName); 
} else { 
    alert("当前无被打开的文件,程序退出");
}



// 实现简化版 JSON.stringify 函数
function stringify(obj) {
    if (typeof obj !== "object" || obj === null) {
        if (typeof obj === "string") return '"' + obj + '"';
        else return String(obj);
    } else {
        var json = [];
        var isArrayCheck = isArray(obj);  // 使用手动实现的 isArray 函数
        for (var key in obj) {
            var value = obj[key];
            var type = typeof value;
            var keyStr = isArrayCheck ? "" : '"' + key + '":';
            if (type === "object" && value !== null) {
                json.push(keyStr + stringify(value)); // 递归处理对象
            } else if (type === "string") {
                json.push(keyStr + '"' + value + '"'); // 处理字符串
            } else {
                json.push(keyStr + String(value)); // 处理数字或布尔值
            }
        }
        return (isArrayCheck ? "[" : "{") + json.join(",") + (isArrayCheck ? "]" : "}");
    }
}

// 手动实现 isArray 函数
function isArray(obj) {
    return obj && obj.constructor === Array;
}

// RGB 转 HEX 函数
function rgbToHex(r, g, b) {
    return "#" + ((1 << 24) | (r << 16) | (g << 8) | b).toString(16).slice(1).toUpperCase();
}

单条导入文本配置.jsx



if (app.documents.length > 0) {  
    // 从桌面选择 JSON 文件
    var jsonFile = File.openDialog("请选择一个配置好的批量JSON文件", "*.json");
    if (jsonFile !== null) {
        jsonFile.open("r");
        var jsonData = jsonFile.read();
        jsonFile.close();

        // 解析 JSON 数据
        var textData = parseJson(jsonData); // 使用手动实现的 parseJson 函数

        // 获取文档中的所有文本框
        var doc = app.activeDocument;
        var textItems = doc.textFrames;

        // 遍历 JSON 数据,更新相应的文本框内容及样式
        for (var i = 0; i < textData.length; i++) {
            var textObject = textData[i];
            if (i < textItems.length) {
                var textFrame = textItems[i];
                textFrame.contents = textObject.content; // 更新文本框内容
                
                // 更新文本样式
                var charAttributes = textFrame.textRange.characterAttributes;
                
                // 验证字体是否存在
                try {
                    var font = app.textFonts.getByName(textObject.font);
                    charAttributes.textFont = font; // 设置字体
                } catch (e) {
                    alert("字体没有找到:" + textObject.font," 改用默认字体Arial-Black" ); 
                    // 使用默认字体
                    charAttributes.textFont = app.textFonts.getByName("Arial-Black"); // 或其他默认字体
                }

                charAttributes.size = textObject.size;

                // 将 HEX 颜色转换为 RGB
                var rgbColor = hexToRgb(textObject.fillColor);
                var fillColor = new RGBColor();
                fillColor.red = rgbColor.r;
                fillColor.green = rgbColor.g;
                fillColor.blue = rgbColor.b;
                charAttributes.fillColor = fillColor;
            }
        }

        // 提示用户操作已完成
        
        alert("恭喜,文本信息已替换"); 
    } else {
        alert("没有选择JSON文件,程序退出");
    }

}else { 
    alert("当前无被打开的文件,程序退出");
}

// 简单实现 JSON.parse
function parseJson(jsonString) {
    return eval('(' + jsonString + ')'); // 使用 eval 函数解析 JSON 字符串
}

// HEX 转 RGB 函数
function hexToRgb(hex) {
    var bigint = parseInt(hex.slice(1), 16);
    var r = (bigint >> 16) & 255;
    var g = (bigint >> 8) & 255;
    var b = bigint & 255;
    return { r: r, g: g, b: b };
}

批量

批量导出文本配置.jsx

// 获取当前文档中的所有文本框
var doc = app.activeDocument;
var textItems = doc.textFrames;
var allTextData = [];

// 选择国家语言
var languages = ["Chinese", "English", "Spanish", "French", "German"]; // 可以根据需要添加更多语言
var selectedLanguages = getSelectedLanguages(languages);

if (selectedLanguages.length > 0) {
    // 为每种语言创建一个对象
    for (var j = 0; j < selectedLanguages.length; j++) {
        var lang = selectedLanguages[j];
        var languageData = {
            language: lang,
            text_list: []
        };

        // 遍历所有文本框,并将文本内容与样式存储为对象
        for (var i = 0; i < textItems.length; i++) {
            var textFrame = textItems[i];

            // 创建文本对象
            var textObject = {
                id: i , // 使用 i + 1 作为 ID
                content: textFrame.contents,
                font: textFrame.textRange.characterAttributes.textFont.name,
                size: textFrame.textRange.characterAttributes.size,
                fillColor: rgbToHex(textFrame.textRange.characterAttributes.fillColor.red, 
                                    textFrame.textRange.characterAttributes.fillColor.green, 
                                    textFrame.textRange.characterAttributes.fillColor.blue)
            };
            languageData.text_list.push(textObject); // 将文本对象添加到当前语言的文本列表中
        }

        allTextData.push(languageData); // 将语言对象添加到总数据中
    }

    // 使用手动实现的 stringify 替代 JSON.stringify
    var jsonString = stringify(allTextData);

    // 保存 JSON 文件到桌面,并设置为 UTF-8 编码
    var file = new File(Folder.desktop + "/ai批量文本配置.json");
    file.encoding = "UTF-8";  // 设置文件编码为 UTF-8
    file.open("w");
    file.write(jsonString);
    file.close();

    // 提示用户文件已导出
    alert("文件已经导出到:" + file.fsName);
} else {
    alert("当前无被打开的文件,程序退出");
}

// 实现简单版 JSON.stringify 函数
function stringify(obj) {
    if (typeof obj !== "object" || obj === null) {
        if (typeof obj === "string") return '"' + obj + '"';
        else return String(obj);
    } else {
        var json = [];
        var isArrayCheck = isArray(obj);  // 使用手动实现的 isArray 函数
        for (var key in obj) {
            var value = obj[key];
            var type = typeof value;
            var keyStr = isArrayCheck ? "" : '"' + key + '":';
            if (type === "object" && value !== null) {
                json.push(keyStr + stringify(value)); // 递归处理对象
            } else if (type === "string") {
                json.push(keyStr + '"' + value + '"'); // 处理字符串
            } else {
                json.push(keyStr + String(value)); // 处理数字或布尔值
            }
        }
        return (isArrayCheck ? "[" : "{") + json.join(",") + (isArrayCheck ? "]" : "}");
    }
}

// RGB 转 HEX 函数
function rgbToHex(r, g, b) {
    return "#" + ((1 << 24) | (r << 16) | (g << 8) | b).toString(16).slice(1).toUpperCase();
}

// 获取用户选择的语言
function getSelectedLanguages(languages) {
    var dialog = new Window('dialog', '选择语言');
    var selected = [];

    // 创建复选框
    for (var i = 0; i < languages.length; i++) {
        dialog.add('checkbox', undefined, languages[i]);
    }

    dialog.add('button', undefined, 'OK');
    dialog.show();

    // 收集选中的语言
    for (var i = 0; i < languages.length; i++) {
        if (dialog.children[i].value) {
            selected.push(languages[i]);
        }
    }
    return selected;
}

// 手动实现的 isArray 函数
function isArray(obj) {
    return Object.prototype.toString.call(obj) === "[object Array]";
}

批量导入文本配置.jsx

// 检查是否有文档打开
if (app.documents.length > 0) {
    var doc = app.activeDocument; // 获取当前活动文档
        // 选择要导入的 JSON 配置文件
        var jsonFile = File.openDialog("请选择一个配置好的语言的JSON文件", "*.json");
        if (jsonFile !== null) {
            // 选择导出的路径
            var exportPath = Folder.selectDialog("请选择一个导出的文件夹");
            if (exportPath !== null) {
      
            jsonFile.open("r");
            var jsonData = jsonFile.read();
            jsonFile.close();

            // 解析 JSON 数据
            var textData = parseJson(jsonData); // 使用手动实现的 parseJson 函数

            // 遍历 JSON 数据,更新相应的文本框内容及样式
            for (var i = 0; i < textData.length; i++) {
                var languageData = textData[i];
                var textList = languageData.text_list;
                var languageName = languageData['language'];

                // 获取当前文档的文本框
                var textItems = doc.textFrames;

                // 确保文本框数量和文本内容匹配
                for (var j = 0; j < textList.length && j < textItems.length; j++) {
                    var textObject = textList[j];
                    var textFrame = textItems[j];
                    textFrame.contents = textObject.content; // 更新文本框内容

                    // 确保文本框有内容再设置样式
                    if (textFrame.contents.length > 0) {
                        var charAttributes = textFrame.textRange.characterAttributes;

                        // 验证字体是否存在
                        try {
                            var font = app.textFonts.getByName(textObject.font);
                            charAttributes.textFont = font; // 设置字体
                        } catch (e) {
                            alert("字体没有找到:" + textObject.font );
                            // 使用默认字体
                            charAttributes.textFont = app.textFonts.getByName("Arial-Black"); // 或其他默认字体
                        }

                        charAttributes.size = textObject.size;

                        // 将 HEX 颜色转换为 RGB
                        var rgbColor = hexToRgb(textObject.fillColor);
                        var fillColor = new RGBColor();
                        fillColor.red = rgbColor.r;
                        fillColor.green = rgbColor.g;
                        fillColor.blue = rgbColor.b;
                        charAttributes.fillColor = fillColor;
                    } else {
                        alert(languageName+":没有找到要设置的文本信息,id为" + textObject.id);
                    }
                }

                // 导出新 AI 文件
                var newFile = new File(exportPath + "/" + languageName + '.ai');
                var saveOptions = new IllustratorSaveOptions();
                doc.saveAs(newFile, saveOptions);
            }

            // 提示用户操作已完成
            alert("恭喜,所有文件生成导出到: " + exportPath);
        } else {
            alert("没有选择导出的文件夹,程序退出");
        }
    } else { 
        alert("没有选择JSON文件,程序退出");
    }
} else {
    alert("当前无被打开的文件,程序退出");
}

// 简单实现 JSON.parse
function parseJson(jsonString) {
    return eval('(' + jsonString + ')'); // 使用 eval 函数解析 JSON 字符串
}

// HEX 转 RGB 函数
function hexToRgb(hex) {
    var bigint = parseInt(hex.slice(1), 16);
    var r = (bigint >> 16) & 255;
    var g = (bigint >> 8) & 255;
    var b = bigint & 255;
    return { r: r, g: g, b: b };
}


扩展 excel(csv)

由于json对于一般用户还是不够友善,新增excel的方式导出导入

批量导出excel(csv)

// 获取当前文档中的所有文本框
var doc = app.activeDocument;
var textItems = doc.textFrames;
var allTextData = [];

// 选择国家语言
var languages = ["Chinese", "English", "Spanish", "French", "German"]; // 可以根据需要添加更多语言
var selectedLanguages = getSelectedLanguages(languages);

if (selectedLanguages.length > 0) {
    for (var j = 0; j < selectedLanguages.length; j++) {
        var lang = selectedLanguages[j];
        var languageData = {
            language: lang,
            text_list: []
        };

        for (var i = 0; i < textItems.length; i++) {
            var textFrame = textItems[i];

            // 创建文本对象
            var textObject = {
                id: i, // 使用 i + 1 作为 ID
                content: textFrame.contents,
                font: textFrame.textRange.characterAttributes.textFont.name,
                size: textFrame.textRange.characterAttributes.size,
                fillColor: rgbToHex(textFrame.textRange.characterAttributes.fillColor.red, 
                                    textFrame.textRange.characterAttributes.fillColor.green, 
                                    textFrame.textRange.characterAttributes.fillColor.blue)
            };
            languageData.text_list.push(textObject); // 将文本对象添加到当前语言的文本列表中
        }

        allTextData.push(languageData); // 将语言对象添加到总数据中
    }

    // 保存 CSV 文件到桌面,并设置为 UTF-8 编码
    saveAsCsv(allTextData, Folder.desktop + "/ai批量文本配置.csv");

    // 提示用户文件已导出
    alert("文件已经导出到:" + Folder.desktop + "/ai批量文本配置.csv");
} else {
    alert("没有选择任何语言,程序退出");
}

function buildCsvRow(data) {
    var row = [];
    for (var k in data) {
        if (data.hasOwnProperty(k)) {
            var value = data[k];
            // 检查是否为字符串,并处理可能存在的引号和换行符
            if (typeof value === 'string') {
                // 转义引号并包裹整个值以处理换行符和其他特殊字符
                value = '"' + value.replace(/"/g, '""').replace(/\r\n|\r|\n/g, "\n") + '"';
            } else if (value !== null && value !== undefined) {
                // 如果不是字符串且不为空或未定义,则直接转换为字符串
                value = String(value);
            } else {
                // 对于null或undefined,可以设置为空字符串或其他默认值
                value = '';
            }
            row.push(value);
        }
    }
    return row.join(',');
}

function saveAsCsv(textData, filePath) {
    var csvContent = "Language,OriginalId,SplitId,Content,Font,Size,FillColor\n"; // CSV Header

    for (var i = 0; i < textData.length; i++) {
        var languageData = textData[i];
        for (var j = 0; j < languageData.text_list.length; j++) {
            var textObject = languageData.text_list[j];

            // 如果文本内容中有换行符,则进行拆分
            var contents = textObject.content.split(/\r\n|\r|\n/);
            for (var k = 0; k < contents.length; k++) {
                if (contents[k] !== "") { // 忽略空行
                    var row = {
                        Language: String(languageData.language),
                        OriginalId: String(textObject.id),
                        SplitId: String(k), // 拆分后的索引
                        Content: String(contents[k]),
                        Font: String(textObject.font),
                        Size: String(textObject.size),
                        FillColor: String(textObject.fillColor)
                    };
                    csvContent += buildCsvRow(row) + "\n";
                }
            }
        }
    }

    var file = new File(filePath);
    file.encoding = "UTF-8";
    file.open("w");
    file.write(csvContent);
    file.close();
}
function rgbToHex(r, g, b) {
    return "#" + ((1 << 24) | (r << 16) | (g << 8) | b).toString(16).slice(1).toUpperCase();
}

function getSelectedLanguages(languages) {
    var dialog = new Window('dialog', '选择语言');
    var selected = [];

    for (var i = 0; i < languages.length; i++) {
        dialog.add('checkbox', undefined, languages[i]);
    }

    dialog.add('button', undefined, 'OK');
    dialog.show();

    for (var i = 0; i < languages.length; i++) {
        if (dialog.children[i].value) {
            selected.push(languages[i]);
        }
    }
    return selected;
}

批量导入excel

// 检查是否有文档打开
if (app.documents.length > 0) {
    var doc = app.activeDocument; // 获取当前活动文档

    // 选择要导入的 CSV 配置文件
    var csvFile = File.openDialog("请选择一个配置好的语言的CSV文件", "*.csv");
    if (csvFile !== null) {
        // 选择导出的路径
        var exportPath = Folder.selectDialog("请选择一个导出的文件夹");
        if (exportPath !== null) {

            try {
                var csvData = loadFromCsv(csvFile.fsName);

                if (!isArray(csvData)) {
                    throw new Error("加载的数据不是有效的数组");
                }

                for (var i = 0; i < csvData.length; i++) {
                    var textObject = csvData[i];

                    // 获取当前文档的文本框
                    var textItems = doc.textFrames;

                    // 确保文本框数量和文本内容匹配
                    if (parseInt(textObject.Id) < textItems.length) {
                        var textFrame = textItems[parseInt(textObject.Id)];
                        textFrame.contents = textObject.Content; // 更新文本框内容

                        // 确保文本框有内容再设置样式
                        if (textFrame.contents.length > 0) {
                            var charAttributes = textFrame.textRange.characterAttributes;

                            // 验证字体是否存在
                            try {
                                var font = app.textFonts.getByName(textObject.Font);
                                charAttributes.textFont = font; // 设置字体
                            } catch (e) {
                                alert("字体没有找到:" + textObject.Font );
                                // 使用默认字体
                                charAttributes.textFont = app.textFonts.getByName("Arial-Black"); // 或其他默认字体
                            }

                            charAttributes.size = parseFloat(textObject.Size);

                            // 将 HEX 颜色转换为 RGB
                            var rgbColor = hexToRgb(textObject.FillColor);
                            var fillColor = new RGBColor();
                            fillColor.red = rgbColor.r;
                            fillColor.green = rgbColor.g;
                            fillColor.blue = rgbColor.b;
                            charAttributes.fillColor = fillColor;
                        } else {
                            alert("没有找到要设置的文本信息,id为" + textObject.Id);
                        }
                    }
                }

                // 导出新 AI 文件
                var newFile = new File(exportPath + "/" + textObject.Language + '.ai');
                var saveOptions = new IllustratorSaveOptions();
                doc.saveAs(newFile, saveOptions);

                // 提示用户操作已完成
                alert("恭喜,所有文件生成导出到: " + exportPath);
            } catch (error) {
                alert("发生错误:" + error.message);
            }
        } else {
            alert("没有选择导出的文件夹,程序退出");
        }
    } else { 
        alert("没有选择CSV文件,程序退出");
    }
} else {
    alert("当前无被打开的文件,程序退出");
}
function isArray(obj) {
    return Object.prototype.toString.call(obj) === '[object Array]';
}

function parseCsvRow(row) {
    var fields = row.split(/,(?=(?:(?:[^"]*"){2})*[^"]*$)/); // 正确处理包含逗号的字段
    for (var i = 0; i < fields.length; i++) {
        fields[i] = fields[i].replace(/^"|"$/g, ''); // 去除包围的引号
    }
    return fields;
}

function loadFromCsv(filePath) {
    var file = new File(filePath);
    file.open("r");
    var content = file.read();
    file.close();

    var rows = content.split("\n");
    var headers = parseCsvRow(rows.shift()); // 获取表头并移除

    var result = [];
    for (var i = 0; i < rows.length; i++) {
        if (rows[i]) {
            var values = parseCsvRow(rows[i]);
            var obj = {};
            for (var j = 0; j < headers.length; j++) {
                obj[headers[j]] = values[j];
            }
            result.push(obj);
        }
    }
    return result;
}

function hexToRgb(hex) {
    var bigint = parseInt(hex.slice(1), 16);
    var r = (bigint >> 16) & 255;
    var g = (bigint >> 8) & 255;
    var b = bigint & 255;
    return { r: r, g: g, b: b };
}

插件

当然,最理想的交互还是用插件实现。 exchange.adobe.com/apps/browse… 不过很多都是收费的插件。

目前用gpt生成了一下插件代码,但是在m1电脑上无法正常显示插件,待研究

安装插件

将整个插件目录复制到 Adobe CEP 扩展路径:

macOS: ~/Library/Application Support/Adobe/CEP/extensions/
Windows: C:\Program Files (x86)\Common Files\Adobe\CEP\extensions\

确保启用调试模式:


macOS: 在 ~/Library/Preferences/com.adobe.CSXS.10.plist 中添加 {"PlayerDebugMode": "1"}。
Windows: 在注册表 HKEY_CURRENT_USER\Software\Adobe\CSXS.10 下创建一个名为 PlayerDebugMode 的字符串值,值为 1。

重新启动 Illustrator,插件应该出现在 窗口 -> 扩展 菜单中。

结局

设计师用上了我脚本,每天提升了工作效率,有效增加了摸鱼的时间,于是这个月的下午茶她包了。

所有源码

github.com/mjsong07/il…