mcpField
A
adobe-illustrator-scripting

adobe-illustrator-scripting

github.com/github创意与媒体40.5k276 次安装今天更新
代码仓库

关于 adobe-illustrator-scripting

Adobe Illustrator Scripting 是一项指导技能,帮助编写和调试 Illustrator 的 ExtendScript 自动化脚本,面向需要自动处理图稿与文档的用户。它提供对象模型参考和示例脚本,涵盖导出与批处理等任务。

主要功能

  1. 01讲解 Illustrator 脚本对象模型
  2. 02编写和调试 ExtendScript 脚本
  3. 03以代码处理文档、图层、路径和文本
  4. 04提供导出与批处理示例
  5. 05自动生成数据图形并处理打印流程

适用场景

  1. 01编写脚本编辑 Illustrator 文档
  2. 02批量处理文件并导出多种格式
  3. 03根据数据集生成图形
  4. 04调试使用 Illustrator DOM 的脚本

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/github/awesome-copilot --skill adobe-illustrator-scripting

安装后在 Claude Code 中输入/adobe-illustrator-scripting确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
object-model-quick-reference.md
scripts/
create-color-grid.jsx
batch-export-png.jsx
find-replace-text.jsx

详细介绍

Adobe Illustrator 脚本编写

通过 ExtendScript(JavaScript/JSX)自动化 Adobe Illustrator 的专业指南。本技能涵盖 Illustrator 脚本对象模型、所有主要 API 对象、代码模式,以及编写生产级 .jsx 脚本的最佳实践。

捆绑资源

  • references/object-model-quick-reference.md:在编写或调试脚本时,可将其用作 Illustrator 脚本对象模型、常见文档和页面项类型及相关 DOM 概念的快速查询参考。
  • scripts/:包含示例 Illustrator 自动化脚本,可作为常见任务(如文档操作、导出、批处理和 DOM 使用)的起点或实现模式。当你需要可用的 JSX 模式,或希望在调试时对比行为时,可查看并调整这些示例。

何时使用本技能

  • 编写新的 Illustrator 自动化脚本(.jsx 或 .js 文件)
  • 调试或修复现有的 Illustrator ExtendScript 代码
  • 以编程方式操作文档、图层、页面项、路径、文本或颜色
  • 批处理 Illustrator 文件或根据数据生成图稿
  • 将文档导出为各种格式(PDF、SVG、PNG、EPS 等)
  • 使用 Illustrator DOM(Application、Document、Layer、PathItem、TextFrame 等)
  • 使用变量和数据集创建数据驱动的图形
  • 通过脚本化打印选项自动化打印工作流

前提条件

  • 已安装 Adobe Illustrator CC 或更高版本
  • 基本 JavaScript 知识(ExtendScript 基于 ES3,并带有 Adobe 扩展)
  • 脚本可通过文件 > 脚本 > 其他脚本、脚本菜单执行,或放入启动脚本文件夹
  • 可使用 ExtendScript Toolkit(ESTK)或任意文本编辑器编写 .jsx 文件

脚本环境

语言和文件扩展名
语言扩展名平台
ExtendScript/JavaScript.jsx、.jsWindows、macOS
AppleScript.scpt仅 macOS
VBScript.vbs仅 Windows

本技能聚焦于 ExtendScript/JavaScript,因为它是跨平台且使用最广泛的选项。

执行脚本
  • 脚本菜单:文件 > 脚本 会列出应用程序脚本文件夹中的脚本
  • 其他脚本:文件 > 脚本 > 其他脚本 可浏览并运行任意 .jsx 文件
  • 启动脚本:将脚本放入启动脚本文件夹,可在启动时自动运行
  • 目标指令:从 ESTK 或外部工具运行时,在脚本开头使用 #target illustrator
  • #targetengine 指令:使用 #targetengine "session" 可在多次脚本执行之间保留变量
  • 外部调用:脚本经常从 Illustrator 外部启动——通过 shell 脚本、任务运行器、CI 任务、ExtendScript Toolkit(ExtendScript Toolkit.exe -run script.jsx),或其他 Adobe 应用发送的 BridgeTalk 消息。参见 外部调用与参数传递。
命名约定(JavaScript)
  • 对象和属性使用 camelCase:activeDocument、pathItems、textFrames
  • app 全局变量引用 Application 对象
  • 集合索引从 零开始:documents[0] 是最前面的文档
  • 使用 typename 属性在运行时识别对象类型

对象模型概览

Illustrator DOM 遵循严格的包含层级:

Application (app)
├── activeDocument / documents[]
│   ├── layers[]
│   │   ├── pageItems[] (all artwork)
│   │   ├── pathItems[]
│   │   ├── compoundPathItems[]
│   │   ├── textFrames[]
│   │   ├── placedItems[]
│   │   ├── rasterItems[]
│   │   ├── meshItems[]
│   │   ├── pluginItems[]
│   │   ├── graphItems[]
│   │   ├── symbolItems[]
│   │   ├── nonNativeItems[]
│   │   ├── legacyTextItems[]
│   │   └── groupItems[]
│   ├── artboards[]
│   ├── views[]
│   ├── selection (array of selected items)
│   ├── swatches[], spots[], gradients[], patterns[]
│   ├── graphicStyles[], brushes[], symbols[]
│   ├── textFonts[] (via app.textFonts)
│   ├── stories[], characterStyles[], paragraphStyles[]
│   ├── variables[], datasets[]
│   └── inkList[], printOptions
├── preferences
├── printerList[]
└── textFonts[]
顶层对象
  • Application(app):根对象。提供对文档、首选项、字体和打印机的访问。关键属性:activeDocument、documents、textFonts、printerList、userInteractionLevel、version。
  • Document:表示一个打开的 .ai 文件。关键属性:layers、pageItems、selection、activeLayer、width、height、rulerOrigin、documentColorSpace。关键方法:saveAs()、exportFile()、close()、print()。
  • Layer:一个绘图图层。关键属性:pageItems、pathItems、textFrames、visible、locked、opacity、name、zOrderPosition、color。

测量单位与坐标

单位

所有脚本 API 值均使用 点(72 点 = 1 英寸)。转换其他单位:

单位转换
英寸乘以 72
厘米乘以 28.346
毫米乘以 2.834645
派卡乘以 12

字距调整、字距和 aki 属性使用 em 单位(千分之一 em,与字体大小成比例)。

坐标系
  • 对于脚本化文档,原点 (0,0) 位于画板的左下角
  • X 从左向右增加;Y 从下向上增加
  • 页面项的 position 属性是其边界框的左上角,表示为 [x, y]
  • 页面项的最大宽度/高度:16348 点
图稿项边界

每个页面项都有三个边界矩形:

  • geometricBounds:不包含描边宽度 [left, top, right, bottom]
  • visibleBounds:包含描边宽度
  • controlBounds:包含控制点/方向点

处理文档

创建与打开
// Create a new document
var doc = app.documents.add();

// Create with a preset
var preset = new DocumentPreset();
preset.width = 612;  // 8.5 inches
preset.height = 792; // 11 inches
preset.colorMode = DocumentColorSpace.CMYK;
var doc = app.documents.addDocument("Print", preset);

// Open an existing file
var fileRef = new File("/path/to/file.ai");
var doc = app.open(fileRef);
保存与导出
// Save as Illustrator format
var saveOpts = new IllustratorSaveOptions();
saveOpts.compatibility = Compatibility.ILLUSTRATOR17; // CC
doc.saveAs(new File("/path/to/output.ai"), saveOpts);

// Export as PDF
var pdfOpts = new PDFSaveOptions();
pdfOpts.compatibility = PDFCompatibility.ACROBAT7;
pdfOpts.preserveEditability = false;
doc.saveAs(new File("/path/to/output.pdf"), pdfOpts);

// Export as PNG
var pngOpts = new ExportOptionsPNG24();
pngOpts.horizontalScale = 300;
pngOpts.verticalScale = 300;
pngOpts.transparency = true;
doc.exportFile(new File("/path/to/output.png"), ExportType.PNG24, pngOpts);

// Export as SVG
var svgOpts = new ExportOptionsSVG();
svgOpts.fontType = SVGFontType.OUTLINEFONT;
doc.exportFile(new File("/path/to/output.svg"), ExportType.SVG, svgOpts);

处理路径与形状

内置形状方法

pathItems 集合为常见形状提供了便捷方法:

var doc = app.activeDocument;
var layer = doc.activeLayer;

// Rectangle: rectangle(top, left, width, height)
var rect = layer.pathItems.rectangle(500, 100, 200, 150);

// Rounded rectangle: roundedRectangle(top, left, width, height, hRadius, vRadius)
var rrect = layer.pathItems.roundedRectangle(500, 100, 200, 150, 20, 20);

// Ellipse: ellipse(top, left, width, height)
var oval = layer.pathItems.ellipse(400, 200, 100, 100);

// Polygon: polygon(centerX, centerY, radius, sides)
var hex = layer.pathItems.polygon(300, 300, 50, 6);

// Star: star(centerX, centerY, radius, innerRadius, points)
var star = layer.pathItems.star(300, 300, 50, 25, 5);
使用坐标数组的自由路径
var doc = app.activeDocument;
var path = doc.pathItems.add();
path.setEntirePath([[100, 100], [200, 200], [300, 100]]);
path.closed = false;
path.stroked = true;
path.strokeWidth = 2;
使用 PathPoint 对象的自由路径
var doc = app.activeDocument;
var path = doc.pathItems.add();

var point1 = path.pathPoints.add();
point1.anchor = [100, 100];
point1.leftDirection = [100, 100];
point1.rightDirection = [150, 150];
point1.pointType = PointType.SMOOTH;

var point2 = path.pathPoints.add();
point2.anchor = [300, 100];
point2.leftDirection = [250, 150];
point2.rightDirection = [300, 100];
point2.pointType = PointType.SMOOTH;

path.closed = false;
路径属性
var item = doc.pathItems[0];
item.filled = true;
item.stroked = true;
item.strokeWidth = 1.5;
item.strokeCap = StrokeCap.ROUNDENDCAP;
item.strokeJoin = StrokeJoin.ROUNDENDJOIN;
item.opacity = 80;
item.closed = true;

处理颜色

颜色对象
// RGB Color (values 0-255)
var red = new RGBColor();
red.red = 255;
red.green = 0;
red.blue = 0;

// CMYK Color (values 0-100)
var cyan = new CMYKColor();
cyan.cyan = 100;
cyan.magenta = 0;
cyan.yellow = 0;
cyan.black = 0;

// Grayscale (0-100, 0 = black)
var gray = new GrayColor();
gray.gray = 50;

// Lab Color
var lab = new LabColor();
lab.l = 50;
lab.a = 20;
lab.b = -30;

// No color (transparent)
var none = new NoColor();
应用颜色
var item = doc.pathItems[0];
item.fillColor = red;
item.strokeColor = cyan;

// Gradient fill
var gradient = doc.gradients.add();
gradient.type = GradientType.LINEAR;
gradient.gradientStops[0].color = red;
gradient.gradientStops[1].color = cyan;

var gradColor = new GradientColor();
gradColor.gradient = gradient;
item.fillColor = gradColor;
专色与色板
// Create a spot color
var spot = doc.spots.add();
spot.name = "My Spot Color";
spot.color = red; // Base color definition

var spotColor = new SpotColor();
spotColor.spot = spot;
spotColor.tint = 100;

item.fillColor = spotColor;

// Access a swatch by name
var swatch = doc.swatches.getByName("PANTONE 185 C");
item.fillColor = swatch.color;

处理文本

文本框架类型
var doc = app.activeDocument;

// Point text
var pointText = doc.textFrames.add();
pointText.contents = "Hello World!";
pointText.position = [100, 500];

// Area text (text inside a path)
var rectPath = doc.pathItems.rectangle(500, 100, 200, 100);
var areaText = doc.textFrames.areaText(rectPath);
areaText.contents = "Text inside a rectangle shape.";

// Path text (text along a path)
var curvePath = doc.pathItems.add();
curvePath.setEntirePath([[50, 300], [150, 400], [250, 300]]);
var pathText = doc.textFrames.pathText(curvePath);
pathText.contents = "Text on a path";
字符与段落格式
var tf = doc.textFrames[0];
var textRange = tf.textRange;

// Character attributes
var charAttr = textRange.characterAttributes;
charAttr.size = 24;           // Font size in points
charAttr.textFont = app.textFonts.getByName("ArialMT");
charAttr.fillColor = red;
charAttr.tracking = 50;       // Em units
charAttr.horizontalScale = 100;
charAttr.verticalScale = 100;
charAttr.baselineShift = 0;

// Paragraph attributes
var paraAttr = textRange.paragraphAttributes;
paraAttr.justification = Justification.CENTER;
paraAttr.firstLineIndent = 0;
paraAttr.leftIndent = 0;
paraAttr.spaceBefore = 0;
paraAttr.spaceAfter = 0;
访问文本内容
var tf = doc.textFrames[0];

// Access sub-ranges
var firstChar = tf.characters[0];
var firstWord = tf.words[0];
var firstPara = tf.paragraphs[0];
var firstLine = tf.lines[0];

// Modify specific ranges
tf.words[0].characterAttributes.size = 36;
tf.paragraphs[0].paragraphAttributes.justification = Justification.LEFT;
串接文本框架
var frame1 = doc.textFrames.areaText(path1);
var frame2 = doc.textFrames.areaText(path2);

// Link frames so text flows from frame1 to frame2
frame1.nextFrame = frame2;

// Stories represent the full text across threaded frames
var storyCount = doc.stories.length;
var fullText = doc.stories[0].textRange.contents;

处理图层

var doc = app.activeDocument;

// Create a layer
var newLayer = doc.layers.add();
newLayer.name = "Background";
newLayer.visible = true;
newLayer.locked = false;
newLayer.opacity = 100;

// Access existing layers
var topLayer = doc.layers[0];
var layerByName = doc.layers.getByName("Background");

// Move items between layers
var item = doc.pathItems[0];
item.move(newLayer, ElementPlacement.PLACEATBEGINNING);

// Reorder layers
newLayer.zOrder(ZOrderMethod.SENDTOBACK);

处理选区

// Get current selection
var sel = app.activeDocument.selection;

// Iterate selected items
for (var i = 0; i < sel.length; i++) {
    var item = sel[i];
    // Check type using typename
    if (item.typename === "PathItem") {
        item.fillColor = red;
    } else if (item.typename === "TextFrame") {
        item.contents = "Modified";
    }
}

// Select an item programmatically
doc.pathItems[0].selected = true;

// Deselect all
doc.selection = null;

处理符号

// Place a symbol instance
var sym = doc.symbols.getByName("MySymbol");
var instance = doc.symbolItems.add(sym);
instance.position = [200, 400];

// Access symbol definition
var symDef = instance.symbol;

// Break link to symbol (expand to regular art)
instance.breakLink();

变换

var item = doc.pathItems[0];

// Rotate 45 degrees around center
item.rotate(45);

// Scale to 50% width, 75% height
item.resize(50, 75);

// Translate (move) by 100 points right and 50 points up
item.translate(100, 50);

// Using a transformation matrix
var matrix = app.getIdentityMatrix();
matrix = app.concatenateRotationMatrix(matrix, 30);
matrix = app.concatenateScaleMatrix(matrix, 150, 150);
item.transform(matrix);

处理画板

var doc = app.activeDocument;

// Access artboards
var ab = doc.artboards[0];
var rect = ab.artboardRect; // [left, top, right, bottom]

// Create a new artboard
var newAB = doc.artboards.add([0, 0, 612, 792]); // Letter size
newAB.name = "Page 2";

// Set active artboard
doc.artboards.setActiveArtboardIndex(1);

数据驱动图形(变量与数据集)

// Variables link document items to data fields
var v = doc.variables.add();
v.kind = VariableKind.TEXTUAL;
v.name = "headline";

// Link a text frame to the variable
var tf = doc.textFrames[0];
tf.contentVariable = v;

// Create datasets for batch content
var ds = doc.dataSets.add();
ds.name = "Version 1";
// Dataset captures current variable bindings

// Switch datasets to swap content
doc.dataSets[0].display();

打印

var doc = app.activeDocument;
var opts = new PrintOptions();

opts.printPreset = "Default";

// Paper options
var paperOpts = new PrintPaperOptions();
paperOpts.name = "Letter";
opts.paperOptions = paperOpts;

// Job options
var jobOpts = new PrintJobOptions();
jobOpts.copies = 1;
jobOpts.designation = PrintArtworkDesignation.VISIBLELAYERS;
opts.jobOptions = jobOpts;

doc.print(opts);

用户交互级别

控制 Illustrator 在脚本执行期间是否显示对话框:

// Suppress all dialogs
app.userInteractionLevel = UserInteractionLevel.DONTDISPLAYALERTS;

// Perform operations that might prompt dialogs...
doc.close(SaveOptions.DONOTSAVECHANGES);

// Restore dialog display
app.userInteractionLevel = UserInteractionLevel.DISPLAYALERTS;

处理方法(JavaScript 专用)

当调用具有多个可选参数的方法时,使用 undefined 跳过中间参数:

// rotate(angle, [changePositions], [changeFillPatterns], [changeFillGradients], ...)
item.rotate(30, undefined, undefined, true);

外部调用与参数传递

Illustrator 脚本通常会从应用程序外部启动 — shell 脚本、调度器、构建流水线、ExtendScript Toolkit,或来自其他 Creative Cloud 应用的 BridgeTalk 消息。在这些启动器下的执行环境与应用内 文件 > 脚本 路径在多个方面存在差异,这些差异经常导致原本正确的代码出错。

在外部启动器下 arguments[] 不可靠

ExtendScript Toolkit 的 -run 调用和 BridgeTalk.send() 不会 将任意启动器参数转发到脚本顶层的 arguments[] 数组中。在许多配置中,该数组包含单个 [object BridgeTalk] 元素,而不是调用方传递的值,如下所示:

// At top of script
var passed = (typeof arguments !== "undefined") ? arguments : [];
for (var i = 0; i < passed.length; i++) {
    $.writeln("arg[" + i + "] = " + passed[i]);
    // Often prints: arg[0] = [object BridgeTalk]
}

当脚本从外部启动时,不要依赖 arguments[] 来获取必需的输入。 请使用以下更可靠的渠道之一。

参数的 Sidecar 文件

当脚本在外部启动器下失败,且错误来源不明显时,退而使用 sidecar 文件:让调用方在已知的绝对路径写入一个小文本文件,并在启动时读取它。无论启动器有何怪癖,这种方式都能奏效,且在运行失败后易于检查。

var SIDECAR_PATH = "C:/Users/userName/job.args.txt";

function readSidecar(path) {
    var f = new File(path);
    if (!f.exists || !f.open("r")) return null;
    var lines = [];
    while (!f.eof) {
        var ln = f.readln();
        if (ln && !/^\s*$/.test(ln)) lines.push(ln);
    }
    f.close();
    return {
        input:  lines[0],
        output: lines[1],
        mode:   lines[2]
    };
}

key=value 格式同样可行,且能避免位置参数的脆弱性:

input=C:/path/to/input.ai
output=C:/path/to/output.pdf
mode=preview
环境变量

$.getenv("NAME") 返回的是 Illustrator 进程可见的环境变量,而非启动器的。如果启动器需要 Illustrator 看到某个值,它必须在启动前将该变量设置为系统级,或写入 Illustrator 的父环境。对于每次调用独立的值,优先使用 sidecar 文件。

$.fileName 与 File($.fileName).parent

在应用内执行时,$.fileName 是正在运行脚本的绝对路径,File($.fileName).parent 会得到脚本所在文件夹。在某些外部启动器下(尤其是 ESTK -run),$.fileName 可能为空,导致相对路径解析静默失败。

// Fragile: returns null under some launchers
var here = $.fileName ? File($.fileName).parent : null;
var sidecar = here ? new File(here.fsName + "/job.args.txt") : null;

// Robust: hardcode a known absolute path or fall back to a stable location
var sidecar = new File("C:/Users/userName/job.args.txt");
if (!sidecar.exists) sidecar = new File(Folder.temp.fsName + "/job.args.txt");
将诊断信息记录到绝对路径

静默失败很常见,因为对话框被抑制,且启动器可能不会呈现 $.writeln 输出。将纯文本日志写入已知的绝对路径,以便运行后可以检查。按需创建父文件夹,这样首次调用就不会因目录缺失而失败。

var LOG_PATH = "C:/Users/userName/logs/job.log";

function log(msg) {
    try {
        var f = new File(LOG_PATH);
        try { if (!f.parent.exists) f.parent.create(); } catch (eDir) {}
        if (f.open("a")) {
            f.writeln("[" + new Date() + "] " + msg);
            f.close();
        }
    } catch (e) {}
}
用 try { ... } catch 包裹入口点

外部启动的脚本常常在没有任何可见提示的情况下失败。在顶层使用 try/catch 将错误写入日志文件,可以把静默失败转化为一行可检查的记录。

try {
    main();
} catch (err) {
    log("FATAL: " + err + (err && err.line ? " line=" + err.line : ""));
}
抑制用户交互

外部调用方无法应答对话框。在任何 DOM 操作之前禁用它们,并在可能以无头方式启动的脚本中完全避免 alert() / confirm() / prompt()。

app.userInteractionLevel = UserInteractionLevel.DONTDISPLAYALERTS;
显式保存

关闭或让 Illustrator 回到空闲状态并不会保存工作文件。在所有 DOM 编辑之后,显式调用 doc.saveAs(...)(或 doc.save()),并记录其是否成功。

var opts = new IllustratorSaveOptions();
opts.compatibility = Compatibility.ILLUSTRATOR17;
doc.saveAs(new File(doc.fullName.fsName), opts);

常见模式

遍历文档中的所有页面项
function processAllItems(doc) {
    for (var i = 0; i < doc.pageItems.length; i++) {
        var item = doc.pageItems[i];
        // Process based on type
        switch (item.typename) {
            case "PathItem":
                // handle path
                break;
            case "TextFrame":
                // handle text
                break;
            case "GroupItem":
                // handle group (may contain nested items)
                break;
        }
    }
}
编辑前递归解锁图层和组

锁定的图层或任何锁定的祖先(父组、剪切组、子图层)都会导致编辑抛出 Error: Target layer cannot be modified。在执行 DOM 修改之前,遍历完整层级并清除 locked / hidden 标志。

function unlockAll(doc) {
    function visitLayers(layers) {
        for (var i = 0; i < layers.length; i++) {
            var lyr = layers[i];
            try { lyr.locked = false; lyr.visible = true; } catch (e) {}
            visitItems(lyr);
            if (lyr.layers && lyr.layers.length) visitLayers(lyr.layers);
        }
    }
    function visitItems(container) {
        var items = container.pageItems;
        for (var j = 0; j < items.length; j++) {
            var it = items[j];
            try { it.locked = false; it.hidden = false; } catch (e) {}
            if (it.typename === "GroupItem") visitItems(it);
        }
    }
    visitLayers(doc.layers);
}
替换链接图像背后的文件(重新链接)

PlacedItem.file = newFile 会替换链接图像,同时保留父级、堆叠顺序,以及(在重新应用后)边界。RasterItem 不暴露可写的 file 属性,因此当占位符是栅格图像时,你必须在同一父级中添加一个新的 PlacedItem,复制边界,然后移除原始对象。

function relinkOrRebuild(item, newFile) {
    var bounds = item.geometricBounds.slice();
    var parent = item.parent;
    var name   = item.name;

    if (item.typename === "PlacedItem") {
        item.file = newFile;
        item.geometricBounds = bounds;
        return item;
    }

    // RasterItem path: rebuild as a linked PlacedItem in the same parent.
    var fresh = parent.placedItems.add();
    fresh.file = newFile;
    fresh.geometricBounds = bounds;
    if (name) try { fresh.name = name; } catch (e) {}
    fresh.move(item, ElementPlacement.PLACEBEFORE);
    item.remove();
    return fresh;
}
放置 SVG 内容(复制/粘贴模式)

PlacedItem.file 接受栅格格式以及 AI/PDF,但不接受 SVG。将其设置为 .svg File 会抛出 Unable to set placed item's file, is the file path provided valid?。将 SVG 图稿带入文档的可靠方式是:将 SVG 作为单独的文档打开,全选,复制,关闭,然后粘贴到工作文档中。

function placeSVG(targetDoc, svgFile, targetLayer) {
    var donor = app.open(svgFile);
    app.executeMenuCommand("selectall");
    app.executeMenuCommand("copy");
    donor.close(SaveOptions.DONOTSAVECHANGES);

    app.activeDocument = targetDoc;
    targetDoc.activeLayer = targetLayer;
    app.executeMenuCommand("pasteFront");

    var sel = targetDoc.selection;
    if (!sel || sel.length === 0) return null;
    if (sel.length === 1) return sel[0];

    // Multiple pasted items: group them so callers get a single handle.
    var group = targetLayer.groupItems.add();
    for (var i = sel.length - 1; i >= 0; i--) {
        sel[i].move(group, ElementPlacement.PLACEATBEGINNING);
    }
    return group;
}
在蒙版组中查找剪切路径

剪切组会将其剪切形状暴露为带有 clipping === true 的子 PathItem(或者,较少见地,为 CompoundPathItem 的子项)。剪切路径的 geometricBounds 给出了用于调整内容尺寸或将内容居中的可见框架。

function findClipPath(group) {
    var items = group.pageItems;
    for (var i = 0; i < items.length; i++) {
        var it = items[i];
        try {
            if (it.typename === "PathItem" && it.clipping) return it;
            if (it.typename === "CompoundPathItem") {
                for (var j = 0; j < it.pathItems.length; j++) {
                    if (it.pathItems[j].clipping) return it;
                }
            }
        } catch (e) {}
    }
    return null;
}
覆盖适应与包含适应尺寸调整

要让图像完全覆盖一个矩形(任何溢出都由蒙版隐藏),使用宽度/高度比例中较大的那个。要让它完全放入其中,使用较小的那个。出血系数(例如 1.10)可让覆盖图像略微超出剪切边缘。

function fitItemToRect(item, rect, mode, bleed) {
    // rect = [L, T, R, B] (Illustrator: T > B)
    var rw = rect[2] - rect[0];
    var rh = rect[1] - rect[3];
    var ib = item.geometricBounds;
    var iw = ib[2] - ib[0];
    var ih = ib[1] - ib[3];
    if (iw <= 0 || ih <= 0) return;

    var sx = rw / iw;
    var sy = rh / ih;
    var s  = (mode === "cover" ? Math.max(sx, sy) : Math.min(sx, sy))
           * (bleed || 1);
    item.resize(s * 100, s * 100);

    var cx = (rect[0] + rect[2]) / 2;
    var cy = (rect[1] + rect[3]) / 2;
    var b  = item.geometricBounds;
    var w  = b[2] - b[0];
    var h  = b[1] - b[3];
    item.position = [cx - w / 2, cy + h / 2];
}
批量处理文件夹中的文件
var folder = Folder.selectDialog("Select folder of .ai files");
if (folder) {
    var files = folder.getFiles("*.ai");
    for (var i = 0; i < files.length; i++) {
        var doc = app.open(files[i]);
        // Process each document...
        doc.close(SaveOptions.DONOTSAVECHANGES);
    }
}
错误处理
try {
    var doc = app.activeDocument;
    var layer = doc.layers.getByName("NonExistentLayer");
} catch (e) {
    alert("Error: " + e.message);
    // e.message, e.line, e.fileName available
}

故障排查

  • "undefined is not an object":通常表示集合为空或索引越界。在访问元素前检查 .length。
  • 脚本运行了但界面上没有任何变化:修改后调用 app.redraw() 强制刷新屏幕。
  • 颜色模式不匹配:文档颜色空间(RGB 与 CMYK)必须与颜色对象匹配。使用 doc.documentColorSpace 检查。
  • 位置看起来不对:请记住脚本化文档使用左下角为原点,Y 轴向上递增。position 属性是边界框的左上角。
  • 文本没有出现:确保文本框尺寸非零。对于点文本,设置 position;对于区域文本,为 areaText() 提供有效路径。
  • Windows 上的文件路径:在路径字符串中使用正斜杠(/)或双反斜杠(\\),或使用 File 对象构造函数。
  • 对话框中断批量脚本:在批量操作前设置 app.userInteractionLevel = UserInteractionLevel.DONTDISPLAYALERTS。
  • 集合使用 getByName():许多集合对象支持 getByName("name"),如果未找到会抛出错误;请用 try/catch 包裹。
  • "Target layer cannot be modified":被锁定的图层、子图层或父组(通常是像 Cover_Mask 这样的剪贴组)阻止了编辑。在修改前,递归清除文档中的 locked 和 hidden。参见在编辑前递归解锁图层和组。
  • "Unable to set placed item's file, is the file path provided valid?":文件存在且路径正确,但 PlacedItem.file 不接受该格式。SVG 是最常见的原因——请改用打开 / 复制 / 粘贴模式。
  • RasterItem.file = newFile 没有任何效果或抛出错误:RasterItem 不暴露可写的 file 属性。向同一父级添加一个新的 PlacedItem,恢复边界和名称,然后 .remove() 该栅格对象。
  • arguments[0] 是 [object BridgeTalk](或为空):脚本是通过 ESTK -run 或 BridgeTalk 消息启动的;位置参数不会被转发。请使用已知绝对路径的附属文件。参见外部调用与参数传递。
  • $.fileName 为空:同样是外部启动器导致的原因。在可能以无头方式调用的脚本中,不要从 $.fileName 推导资源路径——请使用绝对路径或 Folder.temp。
  • 脚本似乎什么也没做:几乎总是以下原因之一:存在锁定的祖先对象、被抑制的对话框吞掉了错误,或编辑后缺少显式的 saveAs。添加一个顶层 try/catch,将日志写入绝对路径,以确认执行并捕获错误。
  • item.resize(sx, sy) 意外地使图稿重新居中:resize 默认围绕元素中心缩放(Transformation.CENTER)。请传入显式的 scaleAbout 参数,或随后用 translate(dx, dy) 重新定位。

脚本常量参考

API 中常用的枚举常量:

类别常量
颜色空间DocumentColorSpace.RGB、DocumentColorSpace.CMYK
对齐方式Justification.LEFT、Justification.CENTER、Justification.RIGHT、Justification.FULLJUSTIFY
点类型PointType.SMOOTH、PointType.CORNER
描边端点StrokeCap.BUTTENDCAP、StrokeCap.ROUNDENDCAP、StrokeCap.PROJECTINGENDCAP
描边连接StrokeJoin.MITERENDJOIN、StrokeJoin.ROUNDENDJOIN、StrokeJoin.BEVELENDJOIN
混合模式BlendModes.NORMAL、BlendModes.MULTIPLY、BlendModes.SCREEN、BlendModes.OVERLAY
保存选项SaveOptions.SAVECHANGES、SaveOptions.DONOTSAVECHANGES、SaveOptions.PROMPTTOSAVECHANGES
导出类型ExportType.PNG24、ExportType.PNG8、ExportType.JPEG、ExportType.SVG、ExportType.TIFF、ExportType.PHOTOSHOP、ExportType.AUTOCAD、ExportType.FLASH
元素放置ElementPlacement.PLACEATBEGINNING、ElementPlacement.PLACEATEND、ElementPlacement.PLACEBEFORE、ElementPlacement.PLACEAFTER、ElementPlacement.INSIDE
Z 顺序ZOrderMethod.BRINGTOFRONT、ZOrderMethod.SENDTOBACK、ZOrderMethod.BRINGFORWARD、ZOrderMethod.SENDBACKWARD
渐变类型GradientType.LINEAR、GradientType.RADIAL
文本框架类型TextType.POINTTEXT、TextType.AREATEXT、TextType.PATHTEXT
变量类型VariableKind.TEXTUAL、VariableKind.IMAGE、VariableKind.VISIBILITY、VariableKind.GRAPH
用户交互UserInteractionLevel.DISPLAYALERTS、UserInteractionLevel.DONTDISPLAYALERTS
兼容性Compatibility.ILLUSTRATOR10 到 Compatibility.ILLUSTRATOR24

JavaScript 对象参考(完整 API 对象列表)

Illustrator JavaScript API 包含以下对象,按类别分组:

核心对象

Application、Document、Documents、DocumentPreset、Layer、Layers、PageItem、PageItems、View、Views、Preferences

路径和形状对象

PathItem、PathItems、PathPoint、PathPoints、CompoundPathItem、CompoundPathItems、GroupItem、GroupItems

文本对象

TextFrame、TextRange、TextRanges、TextPath、Characters、Words、Paragraphs、Lines、InsertionPoint、InsertionPoints、Story、Stories、CharacterAttributes、ParagraphAttributes、CharacterStyle、CharacterStyles、ParagraphStyle、ParagraphStyles、TextFont、TextFonts、TabStopInfo

颜色对象

RGBColor、CMYKColor、GrayColor、LabColor、NoColor、SpotColor、Spot、Spots、PatternColor、GradientColor、Color、Gradient、Gradients、GradientStop、GradientStops

色板和样式对象

Swatch、Swatches、SwatchGroup、SwatchGroups、GraphicStyle、GraphicStyles、Pattern、Patterns、Brush、Brushes

符号对象

Symbol、Symbols、SymbolItem、SymbolItems

画板对象

Artboard、Artboards

置入和栅格对象

PlacedItem、PlacedItems、RasterItem、RasterItems、MeshItem、MeshItems、GraphItem、GraphItems、PluginItem、PluginItems、NonNativeItem、NonNativeItems、LegacyTextItem、LegacyTextItems

数据驱动对象

Variable、Variables、Dataset、Datasets

矩阵和变换对象

Matrix

标签对象

Tag、Tags

描摹对象

TracingObject、TracingOptions

保存和导出选项

IllustratorSaveOptions、EPSSaveOptions、PDFSaveOptions、FXGSaveOptions、ExportOptionsAutoCAD、ExportOptionsFlash、ExportOptionsGIF、ExportOptionsJPEG、ExportOptionsPhotoshop、ExportOptionsPNG8、ExportOptionsPNG24、ExportOptionsSVG、ExportOptionsTIFF

打开选项

OpenOptions、OpenOptionsAutoCAD、OpenOptionsFreeHand、OpenOptionsPhotoshop、PDFFileOptions、PhotoshopFileOptions

打印对象

PrintOptions、PrintJobOptions、PrintPaperOptions、PrintColorManagementOptions、PrintColorSeparationOptions、PrintCoordinateOptions、PrintFlattenerOptions、PrintFontOptions、PrintPageMarksOptions、PrintPostScriptOptions、Printer、PrinterInfo、Paper、PaperInfo、PPDFile、PPDFileInfo、Ink、InkInfo、Screen、ScreenInfo、ScreenSpotFunction

图像和栅格化选项

ImageCaptureOptions、RasterEffectOptions、RasterizeOptions

参考

  • 更新日志 - 最近的脚本 API 变更(CC 2020 新增了 Document.getPageItemFromUuid 和 PageItem.uuid;CC 2017 新增了 Application.getIsFileOpen)
  • Illustrator 脚本指南 - 由社区维护的完整文档

评论

支持 Markdown