ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Photoshop CC JavaScript参考手册实战:ExtendScript脚本与批处理应用

Photoshop CC JavaScript参考手册实战:ExtendScript脚本与批处理应用 简介《Adobe Photoshop CC JavaScript Scripting Reference》是Adobe官方发布的2019年版JavaScript脚本编程参考适用于Windows和Macintosh平台面向希望通过脚本实现自动化批处理、定制扩展功能的Photoshop深度用户和插件开发者。文档系统覆盖Photoshop脚本对象模型、Application/Document/Layer等核心对象以及图层、通道、蒙版、选区、滤镜、色彩模式等API控制方法并深入讲解事件驱动编程模型帮助脚本对用户操作和文档事件做出动态响应。同时提供JavaScript基础语法讲解和多个任务示例便于初学者理解变量、流程控制与函数在实际脚本中的应用。该PDF为单文件文档压缩包约2.19MB虽为英文原版但章节结构清晰、术语完整适合具备一定JavaScript基础的读者进阶查阅。目前已有1595人浏览学习是学习Photoshop脚本开发和自动化工作流的实用参考。1. 一份 2019 年的 PDF为什么现在还有人翻出来用Photoshop 的自动化脚本写过几年的老手都知道官方文档最实用的一直不是那几千页的说明而是按版本号打包的 JavaScript 参考手册。photoshop-cc-javascript-ref-2019.pdf就是 Adobe 随 Photoshop CC 2019 发布的那份 ExtendScript 与 DOM API 文档内容涵盖app、document、layer、File、Folder及 Action Manager 相关接口。很多人以为 CC 版本过时了实际上 2019 之后的大多数批处理脚本仍然在这份参考的覆盖范围之内。这份 PDF 解决的是三类问题不知道某个对象有哪些属性、不知道某个方法要传什么参数、脚本跑起来报错却看不懂错误码。它特别适合那些维护旧脚本、做批量导出、以及把 Photoshop 当作批处理引擎的工程师。正文不会复述整份文档而是讲一套在这份参考上快速做事的方法怎么读对象模型、怎么写可复现的脚本、遇到Error: An unknown error occurred时按什么顺序排查。你手上有没有这份 PDF 都无所谓按本文的代码和参数说明照样能把事情做出来。2. 读懂 Photoshop CC JavaScript 引用手册DOM、BatchPlay 与 ExtendScript 的边界2.1 这份指南在 2019 版里到底收录了什么先明确一个很多人搞混的点photoshop-cc-javascript-ref-2019.pdf不是 ExtendScript 语言参考而是 Photoshop 的 DOM文档对象模型参考。它和 ExtendScript 是两层东西。DOM 层负责操作文档、图层、通道、路径、导出选项ExtendScript 层负责语法、数据类型、File/Folder、Socket等宿主能力。调试时如果报错信息提到ReferenceError: $ is not defined那属于 ExtendScript 语法层问题如果报Error 24: Object is invalid那属于 DOM 层对象失效两者排查方向完全不同。2019 版对应的是 API Version 2019里面有几个值得注意的版本特征。app.version会返回如20.0这类的四位版本号而app.ref.appVersion返回的是用户可见的2019字符串。脚本里判断运行环境时我一般先读app.version.charAt(0)再比对主版本。这套判断逻辑在后续的 2020、2021 里依然兼容但如果你拿到的是简体中文版手册要注意app.preferences里rulerUnits的默认值受到界面语言和首选项影响直接读属性有时候不准。能力域手册中的主要对象常见用途文档操作app.activeDocument、Document新建、打开、保存、导出图层操作Layer、LayerSet遍历、复制、合并、设置效果选区与通道Selection、Channel读取像素、存储选区文件系统File、Folder、openDialog批量文件处理动作模拟ActionManager、executeAction调用菜单命令与插件功能2.2 从 docRef 到 app.activeDocument先厘清对象模型用这本手册最快的切入方式不是从头读而是先理解它给出的docRef约定。手册里大量示例以var doc app.activeDocument;开头后续所有操作都挂在这个 doc 上。这样做有两个实际原因一是避免每次访问app.activeDocument时触发一次宿主调用性能差异在小脚本里无所谓但在千张图片的批处理里会被放大二是中间如果执行了doc.close()再访问app.activeDocument可能已经指向别的文档脚本就错乱了。对象模型有一条清晰的层级链app-document-layer/channel/historyState- 属性与动作。写脚本时遵循一个原则尽量拿到对象引用后就存成局部变量不要反复从根节点往下查。下面是一个最小可跑的示例#target photoshop // 遍历当前文档所有图层的名称 var doc app.activeDocument; var layers doc.layers; for (var i 0; i layers.length; i) { $.writeln(layers[i].name); }这段代码的作用是把当前选中文档的所有顶层图层名打印到控制台。#target photoshop指示 ExtendScript 引擎把脚本路由到 Photoshop 宿主而不是 Illustrator 或其他应用程序doc.layers返回的是一个数组对象layers.length给出顶层图层数量。注意这里只遍历了顶层图层如果文档里有图层组组内图层不会出现在这个数组里必须递归处理这在后面章节展开。2.3 引用了手册却不生效先分清 ExtendScript 与 ScriptUI2.3.1 两种运行环境与调试入口Photoshop 的 JavaScript 脚本可以运行在两种环境一是 ExtendScript Toolkit旧版或 Visual Studio Code 搭配插件二是 Photoshop 内置的“脚本事件管理器”。2019 版把脚本菜单路径放在“文件 脚本”下脚本文件放对目录后可以出现在菜单底部。手动运行脚本的方式是File Scripts Browse选到.jsx文件即可。调试时我一般不用菜单而是用以下方式建立快捷入口$.writeln(script start: new Date()); $.writeln(photoshop version: app.version);$.writeln是 ExtendScript 提供的全局方法输出会出现在 ESTK 或 VS Code 调试控制台里。排版时需要注意这行代码如果以//注释开头会被视为注释不会有输出。常见错误是把$误写成$或_导致抛ReferenceError这属于运行时环境差异不是 Photoshop 本身的问题。2.3.2 一个最小可跑脚本的解剖#target photoshop #target engine ecma3 var doc app.documents.add(800, 600, 72, ref-test, NewDocumentMode.RGB); var layer doc.artLayers.add(); layer.name my-layer; app.activeDocument doc;#target engine ecma3指定使用 ECMAScript 3 语法解析这是 ExtendScript 的根本约束。后续代码里不能使用let、const、箭头函数、模板字符串这类 ES6 语法否则在 ESTK 里直接报语法错误。手册中所有示例代码都是 ES3 风格这是很多新手照搬现代 JavaScript 写法后脚本无法运行的原因。NewDocumentMode.RGB是枚举值对应新建文档的颜色模式如果不传这个参数文档会用上次默认模式创建可能产生预期外的颜色空间。提示2019 版及之前版本对 ES3 的兼容是刚性的Array.prototype.forEach可用但Array.from不可用。判断一个语法是否安全就看它是否出现在 ES3 规范里。3. 照着 ref 写脚本文档操作、图层遍历与参数传入3.1 遍历图层的三种写法与性能差异图层遍历是批处理脚本里出现频率最高的需求。手册里Layer对象同时存在layers属性和artLayers属性前者返回包含图层组在内的混合集合后者只返回普通图层。三种写法的选择依据是你要不要处理嵌套结构。第一种是最简单的顺序遍历适合只处理顶层普通图层的场景var doc app.activeDocument; var layers doc.artLayers; for (var i 0; i layers.length; i) { if (layers[i].kind LayerKind.TEXT) { layers[i].textItem.contents updated; } }这段代码把所有顶层普通文本框内容改成updated。LayerKind.TEXT是一个枚举常量比较每个图层的kind属性。逻辑上要注意遍历的同时修改textItem.contents并不会改变图层数量所以这里是安全的但如果遍历过程中要删除或移动图层就必须倒序遍历否则数组下标会错位。第二种是递归遍历处理图层组嵌套function processLayers(container) { for (var i 0; i container.layers.length; i) { var layer container.layers[i]; if (layer.typename LayerSet) { processLayers(layer); } else { $.writeln(layer.name); } } } var doc app.activeDocument; processLayers(doc);递归写法的关键在于判断typename。手册里Layer和LayerSet都在layers集合中typename属性可以帮助区分。要注意container.layers返回的是索引从 0 开始的数组而且数组长度是动态读取的在递归过程中如果脚本逻辑修改了图层结构index会重新计算导致部分图层被跳过这是递归遍历最常见的踩坑点。第三种是使用doc.layers配合for...in遍历这个写法不推荐因为for...in会枚举原型链上的可枚举属性结果里混入非图层字段且顺序不可控。我写脚本时只在前两种之间选择优先递归。3.2 把“参数怎么设”翻译成可读的代码查阅手册时大家最关心的就是方法签名里的参数说明。拿doc.exportDocument来说它接收两个参数exportFile和ExportOptions子类对象。不同导出格式对应不同的 Options 类手册里给的是ExportOptionsSaveForWeb、ExportOptionsPNG24等。参数设错时最常见的报错是Error 25: Parameter is not valid这通常意味着 Options 对象里给了一个不在枚举值范围内的常量。写参数设置代码时要学会用“局部对象 属性赋值”的模式var doc app.activeDocument; var file new File(/path/to/output.png); var options new ExportOptionsSaveForWeb(); options.format SaveDocumentType.PNG; options.PNG8 false; options.quality 100; options.transparency true; doc.exportDocument(file, ExportType.SAVEFORWEB, options);这段代码把当前文档以 PNG 格式导出。new ExportOptionsSaveForWeb()在手册里有明确的构造函数说明它是ExportOptions的子类专门服务于ExportType.SAVEFORWEB。options.quality 100看着直观实际上ExportOptionsSaveForWeb的quality只在导出 JPEG 时才有意义PNG 模式下会被忽略。许多从旧版脚本迁移过来的代码把options.PNG8 false当成立即生效的设置其实它只对后续的exportDocument调用有效。参数设置完成后exportDocument是同步阻塞操作大图导出期间 UI 会卡住这是正常现象。3.3 批量处理时的 Document 与 Action 混用批量场景下纯 DOM 操作往往慢因为每个属性访问都走一次宿主桥接。手册里虽然没有直接给出性能对比但从executeAction的说明可以推断如果某个操作在 Adobe 的“动作”面板里能录制就存在对应的 ActionDescriptor 调用方式。用 Action Manager 写批量脚本比 DOM 快但代码可读性差。var batchFile new Folder(/path/to/images).getFiles(*.jpg); for (var i 0; i batchFile.length; i) { var doc app.open(batchFile[i]); doc.resizeImage(800, null, 72, ResampleMethod.BICUBIC); doc.close(SaveOptions.SAVECHANGES); }这里的doc.resizeImage是 DOM 方法相当于在 UI 里执行“图像大小”对话框。参数顺序是宽度、高度、分辨率、重采样方式null表示按比例缩放时由 Photoshop 根据原图自动计算高度。很多脚本死在这里是因为没注意SaveOptions.SAVECHANGES配合doc.close时会弹出覆盖确认对话框导致脚本挂起等待用户输入。正确做法是在脚本开头设置app.displayDialogs DialogModes.NO;关闭所有对话框。app.displayDialogs DialogModes.NO; // 所有后续操作不弹对话框这一行是几乎所有批量脚本的标配。DialogModes.NO枚举值把 Photoshop 的交互模式切换为静默模式否则close时弹窗会阻塞执行。注意这个设置是全局状态如果脚本后续还想弹出某个对话框需要临时改回DialogModes.ALL。4. 文件读写、批处理与运行时报错排查4.1 File 与 Folder 对象跨平台路径要避开的坑手册里的File和Folder是 ExtendScript 的全局对象它们不依赖 Photoshop但批处理脚本打交道最多。跨平台兼容性集中在路径分隔符上Windows 用反斜杠\macOS 用斜杠/。ExtendScript 两者都接受但不做自动归一化。new File(/path/to/file)在 Windows 上会被解析为当前盘符下的\path\to\file往往不是想要的位置。一个可靠做法是用Folder.selectDialog或File.openDialog让用户选路径避免硬编码var inputFolder Folder.selectDialog(选择源图片文件夹); var outFolder Folder.selectDialog(选择导出文件夹); var files inputFolder.getFiles(/\.(jpe?g|png)$/i);getFiles接受正则表达式注意i标志在 ExtendScript 里可用但写法上要把整个正则作为参数传入。返回的数组元素是File对象不是字符串用file.fsName获取系统原生路径用file.name获取文件名用file.parent获取所在文件夹。这三个属性在拼接输出路径时非常常用。检查脚本为什么找不到文件时先打印这三个值中的一个确认当前工作目录和实际文件位置是否一致。目录操作上有一个容易忽略的点Folder对象的exists属性在路径不存在时返回false但create()方法不会自动创建多级父目录。需要递归创建时用Folder(/a/b/c).create()前先确认/a/b已存在否则会返回false且不产生目录。手册里对create的说明只有一句“Creates a folder”没有提多级目录行为所以我在批处理脚本里干脆每次都把路径结构保证好。4.2 报错信息怎么读-25、-3 与常见错误码Photoshop 的 ExtendScript 报错格式统一为Error: 错误信息 (错误码)其中错误码是关键。手册在开头部分给出了一张错误码表但实际运行中最常遇到的就这么几个错误码含义常见触发场景-25参数无效ExportOptions的枚举值传了不存在的字符串-3文件未找到File对象指向不存在的路径-36未定义名称访问了doc.layers中不存在的图层名-205用户取消Folder.selectDialog被点击了取消Error 24对象无效文档已关闭但仍持有其引用-25的排查思路是逐条检查传给方法的参数类型和枚举值。比如doc.resizeImage(800, null, 72, ResampleMethod.BICUBIC)null是允许的但如果把第二个参数改成0某些版本会直接报参数错误因为 0 在语义上不等于“不指定”。Error 24则是最阴间的一个它一般出现在跨函数传递Document引用时一个函数里close()了文档另一个函数还在用之前存下的引用修图。排查时先看脚本里所有doc.close()之后的代码是否还引用了同一个 doc。还有一种Error: An unknown error occurred没有错误码多半发生在app.open打开损坏文件时或者doc.exportDocument的输出路径没有写入权限。对于输出路径无权限的情况先检查目标文件夹是否在实际存在的位置不要假设脚本运行目录就是当前工程目录。4.3 用日志与断点验证脚本行为脚本报错时不要盯着消息看直接加日志。最实用的是下面这段包装var logFile new File(~/Desktop/script-log.txt); function log(msg) { logFile.open(a); logFile.writeln(new Date().toLocaleString() msg); logFile.close(); }手动运行脚本时$.writeln输出到控制台但批处理场景下控制台不可见写到日志文件才能留痕。log()函数每次调用打开文件追加一行再关闭日志行数多时性能差但排错期间无妨。正式使用时可以改成把内容累积到数组、最后一次性write。关于断点ESTK 里可以在行号处打断点但前提是脚本文件路径里不含中文或空格否则断点经常失效。VS Code 配 ExtendScript 插件后调试体验稍好但要确认插件使用的宿主版本能匹配 Photoshop 2019 的远程调试端口。更快的替代方案是故意制造异常用throw new Error(阶段标记 i)来定位是循环里的哪一次崩溃。try { doc.exportDocument(file, ExportType.SAVEFORWEB, options); } catch (e) { log(导出失败: e file file.fsName); }把可能失败的调用放进try/catch里日志里会带上文件路径。多文件批处理时一个文件失败不能中断整个批次这个模式几乎是必须的。5. 顺着引用手册反向查方法一个提高效率的搜索模式不需要通读整本 PDF而是把手册当作查表工具用“目标功能 - 英文动词 - 手册条目”这个顺序反向检索。想出“把图层复制到新文档”这个动作先拆成主对象Layer、动作duplicate然后在手册索引里找duplicate。手册的目录结构是按对象字母排序的layer.duplicate和document.duplicate是两个不同条目前者多一个目标文档参数。这个方法最高效的一个变体是直接看手册里每个方法下面的 “Example” 段落。2019 版手册在主要方法后面都带示例代码这些示例往往比正文描述更能解释参数意图。看layer.move(relativeObject, ElementPlacement.PLACEATBEGINNING)时先跑一遍示例再改成自己需要的参数。这里的ElementPlacement枚举有四个值PLACEATBEGINNING、PLACEATEND、PLACEATBEFORE、PLACEATAFTER前两个是绝对位置后两个关联到relativeObject弄混时图层顺序会和预期相反。排查“为什么脚本能跑但结果不对”这类问题时手册帮不上太多忙但有一个模式值得养成把操作涉及的对象ref在操作前打印出来。比如var layer doc.artLayers.add(); $.writeln(ref(layer));ref()是 ExtendScript 提供的全局函数返回对象的标识字符串能确认操作的是不是同一个图层。它输出的格式类似[object ArtLayer]如果打印内容是[object Object]或undefined说明引用已经失效。每次在对象操作前后各打印一次对比引用是否变化能定位一大半的“操作没生效”问题。这是往 5 年以上经验级别靠的那类技巧表面上只多了一行实际上把排错成本减半了。本文还有配套的精品资源点击获取
返回列表