关于 adobe-illustrator-scripting
Adobe Illustrator Scripting 是一项指导技能,帮助编写和调试 Illustrator 的 ExtendScript 自动化脚本,面向需要自动处理图稿与文档的用户。它提供对象模型参考和示例脚本,涵盖导出与批处理等任务。
主要功能
- 01讲解 Illustrator 脚本对象模型
- 02编写和调试 ExtendScript 脚本
- 03以代码处理文档、图层、路径和文本
- 04提供导出与批处理示例
- 05自动生成数据图形并处理打印流程
适用场景
- 01编写脚本编辑 Illustrator 文档
- 02批量处理文件并导出多种格式
- 03根据数据集生成图形
- 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.mdscripts/create-color-grid.jsxbatch-export-png.jsxfind-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、.js | Windows、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 脚本指南 - 由社区维护的完整文档