0
点赞
收藏
分享

微信扫一扫

AEJoy—— 使用 JS 脚本创建预合成(四)


这是由 Brian Maffitt 设计出的一个很实用的脚本。当你想将一个或多个图层创建预合成时,产生的新合成会占用当前合成的长度,而嵌入的剪辑的持续时间则会相应被隐藏。这个脚本搭配 “Move all attributes…” 选项,将一个或多个选定的层进行预合成,产生的新的 comp 的 In Point 将是选定层最早的 In Point ,同样该 comp 的 Out Point 将是选定层最晚的 Out Point。如果你只选择一个层,新的 comp 的持续时间和开始时间是与层相匹配的。

分步代码解析

范围限定

首先要注意的是,我们将脚本封装在标准作用域限制的大括号和撤销组中:

{

// create undo group
app.beginUndoGroup("Pre-Compose to Layer Duration");

[the rest of the script goes in here]

app.endUndoGroup();
}

如果你不确定我们为什么要这样做,请参考这篇文章《​​AEJoy—— JS 脚本的代码管理好习惯(三)​​》。

测试分支条件

脚本的实际主体以两个条件测试开始,如果没有满足这些测试,脚本将以两个错误消息中的一个退出。这是通过两个嵌套的 if/else 结构来完成的,它们像这样包围了脚本的其余部分:

// select the active item in the project window
// and make sure it's a comp

var myComp = app.project.activeItem;
if(myComp instanceof CompItem) {

// make sure one or more layers are selected

var myLayers = myComp.selectedLayers;
if(myLayers.length > 0){

[the rest of the script goes in here]

}else{
alert("select at least one layer to precompose.");
}
}else{
alert("please select a composition.");
}

这段代码的第一行(忽略注释)创建了一个名为 “myComp” 的新对象,该对象被设置为项目窗口中的活动项(activeItem)的值。我们假设它是一个 comp,但我们需要确保(不会发生以下情形) —— 因为如果它不是,而我们仍然继续执行的话,脚本将中止(这种执行形式总是比较糟糕的)。因此,下一行代码将使用 JavaScript 操作符 “instanceof” 来测试 “myComp” 是否是一个类型为 “CompItem” 的对象。如果是,脚本继续执行下一个语句,如果不是,执行跳转到代码末尾的警告(第一个 if /else 的 “else” 子句),并为用户生成一个错误消息对话框,如下所示:

AEJoy—— 使用 JS 脚本创建预合成(四)_原力计划

在第二个测试中,我们创建了一个名为 “myLayers” 的新对象,它构成了 “myComp” 中选中的图层集合。然后我们测试 “myLayers” 的长度,如果有任何层被选中,那么该值将大于零。如果是这样的话,则继续执行脚本的其余部分。如果不满足条件,则弹出警告,显示如下对话框:

AEJoy—— 使用 JS 脚本创建预合成(四)_原力计划_02

因此,如果没有满足运行脚本的任何要求,就会显示适当的有帮助的对话框,脚本会优雅地退出,而不做任何事情。

脚本执行前后对比

在进入代码的真正核心之前,让我们看看成功运行脚本应该是什么样子的。这是我们运行脚本前的两个图层的小合成:

脚本执行前:

AEJoy—— 使用 JS 脚本创建预合成(四)_javascript_03

脚本执行后:

AEJoy—— 使用 JS 脚本创建预合成(四)_After Effect_04

注意,三个被选中的图层已经被一个名为 “comp R Arm” 的预合成替换了。新 comp 的名字是通过将第一个选中的图层的名字连接到 comp 来构建的。注意,新的合成被修剪,以精确地适合所选图层们的合并持续时间。

回到代码

好的,让我们来看看建立和创建新的预合成的代码块。这是第一部分:

// set new comp's default In and Out points to those of first layer

var newInPoint = myLayers[0].inPoint;
var newOutPoint = myLayers[0].outPoint;

在这里,我们只是设置了两个新变量,它们最终将成为新 comp 的 InPoint 和 OutPoint 。记住“myLayers” 是一个对象,它包含了所选图层的集合。结果是,这些是按它们被选中的顺序排列的——所以 myLayers[0] 是第一个被选中的图层。

稍后在代码中,我们会看到每个选中的层,并决定我们是否应该使用它的 InPoint 或 OutPoint ,这里我们只是初始化这些变量,稍后我们会比较一些东西。

命名该预合成

下一段代码为新 comp 创建了名称,代码如下:

// create new comp name of "comp " plus name of first layer

var newCompName = "comp ";
var layerName = myLayers[0].name;
if(layerName.length > 26) {
layerName = layerName.substring(0, 26);
}
newCompName += layerName;

首先,我们创建一个名为 “newCompName” 的字符串变量,并将其初始化为字符串 “comp” 。然后我们创建另一个名为 “layerName” 的字符串变量,并将其设置为选中图层集合 “myLayers” 中第一个选中的图层的名称。然后我们检查层名是否超过 26 个字符。我们这样做是因为 AE 最大层名长度为 31 个字符,我们将使用 “comp” 中的 5 个字符。如果层名超过 26 个字符,我们只使用前 26 个字符。然后我们添加图层名称(或前 26 个字符)到 “comp” 来创建新的图层名称。

创建一个层索引的数组

构造 “预合成” 的方法, 我们需要更进一步的代码,其中一个输 —— 一个数组, 其包含将被移动到新的 comp 的层索引。这里我们将通过遍历选择层的集合来构建数组, 选择它们的层索引值并将它们添加到数组中。这也是我们对所选层进行循环遍历的地方,以确定最早的层 InPoint 和最晚的 OutPoint 。这是代码:

// "precompose" expects an array of layer indices

var layerIndices = new Array();
for (var i = 0; i < myLayers.length; i++) {
layerIndices[layerIndices.length] = myLayers[i].index;

// make sure new comp In point is In point of earliest layer
// and new comp Out point is Out point of latest layer

if (myLayers[i].inPoint < newInPoint) newInPoint = myLayers[i].inPoint;
if (myLayers[i].outPoint > newOutPoint) newOutPoint = myLayers[i].outPoint;
}

创建合成

现在我们有了创建新合成所需的一切,这里我们使用图层集合对象的 “预合成” 方法来预合成选中的图层。“precomp” 需要三个参数。


  • 第一个是要被预合成的层的层索引数组;
  • 第二个是新合成的名称;
  • 如果你想要预合成选项 “Move all attributes into the new composition”,你可以设置第三个参数为 “true”,就像我们在本例中做的那样。

下面是创建新 comp 的代码:

// create the new comp

var newComp = myComp.layers.precompose(layerIndices, newCompName, true );

设置新合成的 InPoint 和 OutPoint

至此,我们选择层已经被我们的新合成替代了。我们需要做的最后一件事是在新 comp 中设置 InPoint 和 OutPoint。事实证明, 这种新的 comp 将是在旧 comp 中选中的层。所以我们创建一个新的对象 “preCompLayer” 并设置它等于在旧 comp 当前选中的层(此时已是新的 comp )。变量 “newInPoint” 有我们需要的新 comp 的 InPoint 的值,变量 “newOutPoint” 有我们需要的新 comp 的 OutPoint 的值。下面是我们需要为新 comp 设置 inPoint 和 outPoint 属性的代码:

// set in and out points of new comp

var preCompLayer = myComp.selectedLayers[0];
preCompLayer.inPoint = newInPoint;
preCompLayer.outPoint = newOutPoint;

完整的脚本

//
// preCompToLayerDur.jsx (revised 7/26/04)
//
// This script will pre-compose selected layers with "Move all attributes..."
// The in point of the new comp will be the earliest in point of the selected
// layers and the out point will be the latest out point of the selected layers.
//
// The new comp will thus be trimmed so that its duration reflects the composite
// duration of the included layers.
//

// Based on an idea by Brian Maffitt
// Original code design by Keiko Yamada
// Final tweaks and enhancements by Dan Ebberts
//

{

// create undo group

app.beginUndoGroup("Pre-Compose to Layer Duration");

// select the active item in the project window
// and make sure it's a comp

var myComp = app.project.activeItem;
if(myComp instanceof CompItem) {

// make sure one or more layers are selected

var myLayers = myComp.selectedLayers;
if(myLayers.length > 0){

// set new comp's default in and out points to those of first layer

var newInPoint = myLayers[0].inPoint;
var newOutPoint = myLayers[0].outPoint;

// create new comp name of "comp " plus name of first layer

var newCompName = "comp ";
var layerName = myLayers[0].name;
if(layerName.length > 26) {
layerName = layerName.substring(0, 26);
}
newCompName += layerName;

// "precompose" expects an array of layer indices

var layerIndices = new Array();
for (var i = 0; i < myLayers.length; i++) {
layerIndices[layerIndices.length] = myLayers[i].index;

// make sure new comp in point is in point of earliest layer
// and new comp out point is out point of latest layer

if (myLayers[i].inPoint < newInPoint) newInPoint = myLayers[i].inPoint;
if (myLayers[i].outPoint > newOutPoint) newOutPoint = myLayers[i].outPoint;
}

// create the new comp

var newComp = myComp.layers.precompose(layerIndices, newCompName, true );

// set in and out points of new comp

var preCompLayer = myComp.selectedLayers[0];
preCompLayer.inPoint = newInPoint;
preCompLayer.outPoint = newOutPoint;

}else{
alert("select at least one layer to precompose.");
}
}else{
alert("please select a composition.");
}
app.endUndoGroup();
}

(完)



举报

相关推荐

0 条评论