After Effects 脚本开发
After Effects 脚本开发
Section titled “After Effects 脚本开发”欢迎来到使用 ExtendScript 开发 After Effects 脚本的综合指南。学习如何通过强大的脚本自动化工作流程、创建自定义工具并扩展 After Effects 的功能。
什么是 After Effects 脚本?
Section titled “什么是 After Effects 脚本?”After Effects 脚本是 ExtendScript 程序,可用于自动化任务、操作项目元素并扩展应用程序的功能。它们的范围可以从简单的自动化工具到复杂的工作流程解决方案。
ExtendScript 概述
Section titled “ExtendScript 概述”ExtendScript 是 Adobe 实现的 JavaScript,为 Creative Suite 应用程序提供了附加功能:
- 基于 JavaScript ES3: 熟悉的 JavaScript 语法和概念
- Adobe 扩展: 用于 After Effects 的特殊对象和方法
- 文件系统访问: 在本地系统上读写文件
- UI 创建: 构建自定义用户界面
- 跨平台: 可在 Windows 和 macOS 上运行
在 After Effects 启动时自动运行的脚本,用于初始化和设置。
可通过 文件 > 脚本 菜单访问的脚本,用于按需功能。
ScriptUI 面板
Section titled “ScriptUI 面板”具有自定义用户界面的脚本,可以停靠在 After Effects 工作区中。
在渲染过程中执行的脚本,用于自定义输出处理。
- ExtendScript 工具包 - Adobe 官方 IDE (旧版)
- Visual Studio Code - 带有 ExtendScript 扩展的现代编辑器
- After Effects - 用于测试的目标应用程序
- 文档 - Adobe ExtendScript 和 After Effects 脚本参考
脚本文件夹:
- Windows:
C:\Program Files\Adobe\Adobe After Effects [version]\Support Files\Scripts\ - macOS:
/Applications/Adobe After Effects [version]/Scripts/
ScriptUI 面板:
- Windows:
C:\Program Files\Adobe\Adobe After Effects [version]\Support Files\Scripts\ScriptUI Panels\ - macOS:
/Applications/Adobe After Effects [version]/Scripts/ScriptUI Panels/
基本脚本结构
Section titled “基本脚本结构”简单脚本模板
Section titled “简单脚本模板”// 基本的 After Effects 脚本模板(function() { 'use strict';
// 检查 After Effects 是否可用 if (typeof app === 'undefined') { alert('此脚本需要 After Effects'); return; }
// 主要脚本逻辑 function main() { try { // 您的脚本代码在此处 var comp = app.project.activeItem; if (!comp || !(comp instanceof CompItem)) { alert('请选择一个合成'); return; }
// 示例:创建一个固态层 var solidLayer = comp.layers.addSolid( [1, 0, 0], // 红色 '脚本生成的固态层', comp.width, comp.height, comp.duration );
alert('固态层已创建: ' + solidLayer.name);
} catch (error) { alert('错误: ' + error.toString()); } }
// 执行主函数 main();})();应用程序对象
Section titled “应用程序对象”app 对象是 After Effects 对象模型的根:
// 访问当前项目var project = app.project;
// 获取活动的合成var activeComp = app.project.activeItem;
// 应用程序设置var version = app.version;var language = app.isoLanguage;// 创建新项目app.newProject();
// 保存项目app.project.save(new File('/path/to/project.aep'));
// 导入素材var importFile = new File('/path/to/footage.mov');var footageItem = app.project.importFile(new ImportOptions(importFile));// 创建新合成var newComp = app.project.items.addComp( '我的合成', // 名称 1920, // 宽度 1080, // 高度 1.0, // 像素长宽比 10, // 持续时间 (秒) 30 // 帧率);
// 向合成中添加图层var textLayer = newComp.layers.addText('Hello World');// 访问图层var comp = app.project.activeItem;var firstLayer = comp.layer(1);var layerByName = comp.layer('图层名称');
// 修改图层属性firstLayer.transform.position.setValue([960, 540]);firstLayer.transform.scale.setValue([150, 150]);firstLayer.transform.rotation.setValue(45);
// 添加关键帧var position = firstLayer.transform.position;position.setValueAtTime(0, [100, 100]);position.setValueAtTime(2, [500, 300]);高级脚本技术
Section titled “高级脚本技术”function safeOperation() { try { // 风险操作 var comp = app.project.activeItem; if (!comp) { throw new Error('没有活动的合成'); }
// 继续操作 return comp.layers.addSolid([1, 1, 1], '白色固态层', 100, 100, 1);
} catch (error) { // 优雅地处理错误 $.writeln('safeOperation 中的错误: ' + error.toString()); return null; }}// 将操作分组以便单次撤销app.beginUndoGroup('我的脚本操作');
try { // 此处有多个操作 var comp = app.project.activeItem; var layer1 = comp.layers.addSolid([1, 0, 0], '红色', 100, 100, 1); var layer2 = comp.layers.addSolid([0, 1, 0], '绿色', 100, 100, 1); layer2.transform.position.setValue([200, 200]);
} finally { app.endUndoGroup();}function processLayers() { var comp = app.project.activeItem; if (!comp) return;
var totalLayers = comp.numLayers;
// 创建进度条 var progressPanel = new Window('dialog', '处理图层'); var progressBar = progressPanel.add('progressbar', undefined, 0, totalLayers); var progressText = progressPanel.add('statictext', undefined, '开始中...'); progressPanel.show();
try { for (var i = 1; i <= totalLayers; i++) { // 更新进度 progressBar.value = i; progressText.text = '正在处理 ' + totalLayers + ' 个图层中的第 ' + i + ' 个'; progressPanel.update();
// 处理图层 var layer = comp.layer(i); // 您的处理逻辑在此处
// 短暂延迟以显示进度 $.sleep(100); } } finally { progressPanel.close(); }}ScriptUI 界面创建
Section titled “ScriptUI 界面创建”// 创建 ScriptUI 面板function createPanel(thisObj) { var panel = (thisObj instanceof Panel) ? thisObj : new Window('dialog', '我的脚本面板');
// 添加 UI 元素 var group1 = panel.add('group'); group1.orientation = 'row'; group1.add('statictext', undefined, '图层名称:'); var nameInput = group1.add('edittext', undefined, '新图层'); nameInput.characters = 20;
var group2 = panel.add('group'); group2.orientation = 'row'; var createButton = group2.add('button', undefined, '创建图层'); var cancelButton = group2.add('button', undefined, '取消');
// 按钮事件处理 createButton.onClick = function() { createLayerWithName(nameInput.text); };
cancelButton.onClick = function() { panel.close(); };
// 显示面板 if (panel instanceof Window) { panel.show(); }
return panel;}
function createLayerWithName(name) { var comp = app.project.activeItem; if (comp && comp instanceof CompItem) { var layer = comp.layers.addSolid([Math.random(), Math.random(), Math.random()], name, 100, 100, 1); alert('已创建图层: ' + layer.name); }}
// 执行createPanel(this);function readTextFile(filePath) { var file = new File(filePath); if (file.exists) { file.open('r'); var content = file.read(); file.close(); return content; } return null;}function writeTextFile(filePath, content) { var file = new File(filePath); file.open('w'); file.write(content); file.close();}JSON 数据处理
Section titled “JSON 数据处理”function saveProjectData(data) { var jsonString = JSON.stringify(data, null, 2); var file = File.saveDialog('保存项目数据', '*.json'); if (file) { writeTextFile(file.fsName, jsonString); }}
function loadProjectData() { var file = File.openDialog('加载项目数据', '*.json'); if (file) { var jsonString = readTextFile(file.fsName); return JSON.parse(jsonString); } return null;}高效的图层访问
Section titled “高效的图层访问”// 避免重复访问图层// 差:for (var i = 1; i <= comp.numLayers; i++) { comp.layer(i).transform.position.setValue([100, 100]); comp.layer(i).transform.scale.setValue([50, 50]);}
// 好:for (var i = 1; i <= comp.numLayers; i++) { var layer = comp.layer(i); layer.transform.position.setValue([100, 100]); layer.transform.scale.setValue([50, 50]);}// 使用撤销组以获得更好的性能app.beginUndoGroup('批量创建图层');for (var i = 0; i < 100; i++) { comp.layers.addSolid([Math.random(), Math.random(), Math.random()], '图层 ' + i, 100, 100, 1);}app.endUndoGroup();// 输出到 ExtendScript 工具包控制台$.writeln('调试信息: ' + variable);
// 提醒用户反馈alert('操作完成');
// 确认对话框if (confirm('继续操作?')) { // 用户点击了确定}function logError(error, context) { var logMessage = new Date().toString() + ' - ' + context + ': ' + error.toString(); $.writeln(logMessage);
// 可选地写入文件 var logFile = new File(Folder.desktop + '/ae_script_log.txt'); logFile.open('a'); // 追加模式 logFile.writeln(logMessage); logFile.close();}🔗 相关资源
Section titled “🔗 相关资源”- ExtendScript 工具包设置 - 开发环境
- VS Code 配置 - 现代开发设置
- 脚本示例 - 社区分享的脚本
- Adobe ExtendScript 文档 - 官方参考
- 错误处理: 始终使用 try-catch 块以确保脚本健壮
- 撤销组: 将相关操作分组以获得更好的用户体验
- 进度反馈: 为长时间操作提供进度指示器
- 代码组织: 使用函数和模块以保持代码可维护
- 测试: 使用不同的项目配置测试脚本
- 文档: 为您的代码添加注释以便将来维护