スクリプト内では『〇〇.expression=”なんちゃら”』でエクスプレッションを適用できます。
それ用に「特定のプロパティをエクスプレッション表記にしたものがほしい」ときに使える関数です。
function mGetDotSyntaxForExp( aProp ){
var mProp = aProp;
var mAdrs = [];
//親プロパティを上から順に処理する。
for (var i = mProp.propertyDepth; i >= 1; i--) {
var mPropTmp = mProp.propertyGroup(i);
if( i === mProp.propertyDepth ){
mAdrs.push(mPropTmp.index);
}else{
mAdrs.push(mPropTmp.propertyIndex);
}
}
//自身についての処理。
mAdrs.push(mProp.propertyIndex);
//文字列にする。
var mAdrsStr = mAdrs.join(')(');
mRstAdrsStr = 'thisComp.layer(' + mAdrsStr + ');'
/*
var mSl = mProp.propertyGroup(mProp.propertyDepth);
var mAi = mSl.containingComp;
var mAiName = mAi.name;
mRstAdrsStr = 'comp("' + mAiName + '").layer(' + mAdrsStr + ');'
*/
return mRstAdrsStr;
}
上記の名前参照版。
function mGetDotSyntaxForExpName( aProp ){
var mProp = aProp;
var mAdrs = [];
//親プロパティを上から順に処理する。
for (var i = mProp.propertyDepth; i >= 1; i--) {
var mPropTmp = mProp.propertyGroup(i);
mAdrs.push('"' + mPropTmp.name + '"');
}
//自身についての処理。
mAdrs.push('"' + mProp.name + '"');
//文字列にする。
var mAdrsStr = mAdrs.join(')(');
mRstAdrsStr = 'thisComp.layer(' + mAdrsStr + ');'
/*
var mSl = mProp.propertyGroup(mProp.propertyDepth);
var mAi = mSl.containingComp;
var mAiName = mAi.name;
mRstAdrsStr = 'comp("' + mAiName + '").layer(' + mAdrsStr + ');'
*/
return mRstAdrsStr;
}
使い方
スクリプト内で
var 〇〇 = mGetDotSyntaxForExp( aProp );
と書き、aPropに選択したプロパティ、あるいは指定したプロパティを入れれば、〇〇がエクスプレッション用の文字列となります。
*1 後半の/*と*/を消せば、thisCompではなくcomp(”コンポ名”)になります。が、コンポの名前指定は同じ名前が複数あった場合にエラーになりやすいのでおすすめしておりません。
*2 aPropに選択プロパティ(selectedProperties[])を使う場合は、『エフェクトのパラメータ等はその1つ上も自動選択されてしまう』ことに注意してください。自動で2つ選択されてしまうプロパティの場合は、selectedProperties[0]ではなくselectedProperties[1]を入れる必要があります。
その1
//上記のmGetDotSyntaxForExp関数の前か後に以下を書く。
var mAi = app.project.activeItem;
var mSl = mAi.selectedLayers[0];
var mSp = mSl.selectedProperties[0];
var mDotStxStr = mGetDotSyntaxForExp( mSp );
prompt("",mDotStxStr);
あるプロパティを選択しておいてこのスクリプトを実行します。すると画面が出て、コピペができるエクスプレッション用文字列がでます。STEP1の*2に注意してください。
その2
//上記のmGetDotSyntaxForExp関数の前か後に以下を書く。
var mAi = app.project.activeItem;
var mSl = mAi.selectedLayers[0];
var mSp = mSl.selectedProperties[0];
var mDotStxStr = mGetDotSyntaxForExp( mSp );
var mNull = mAi.layers.addNull();
mNull.position.expression = '' +
'var targetProp = ' + mDotStxStr + '\n' +
'targetProp;';
あるレイヤーの位置パラメータを選択しておいてこのスクリプトを実行します。すると、ヌルを作ってそのヌルの位置にエクスプレッションを作り、レイヤーの位置パラメータの場所を記述してくれます。
使いどころ
エクスプレッションを適用するスクリプトや、途中計算にエクスプレッションを使うスクリプトに使えます。
スクリプトでは対応していない関数やメソッドがエクスプレッションでは使えることがあるので、途中計算にエクスプレッションを使うという選択肢があります。また、シェイプ関連の処理もスクリプトよりエクスプレッションのほうがまだわかりやすい印象です。
*追記
プロパティの種類(propertyType)を調べるうち「名前を変えられるものは番号も変わり得る、名前を変えられないものは番号が変わらない」ということがわかりました。名前と番号、どちらを参照するか場合分けする意味がないですね…。
なので名前参照版とインデックス参照版の2つに分けました。それぞれ一長一短ありまして、
名前参照
- 取得したプロパティと同じ階層に同じ名前のプロパティがあった場合、一番上のものを参照してしまう。
- 上記問題が起こらずエクスプレッションを設定できたら、後でユーザーが手動でプロパティ場所や名前を変更しても、AEが自動で追ってくれる。
インデックス参照
- 取得したプロパティと同じ階層に同じ名前のプロパティがあっても正確に参照できる。
- エクスプレッションを設定後にユーザーが手動でプロパティ場所を変更するとエクスプレッションエラーとなる。名前変更については場所を変更しない限りは参照を続ける。
といった具合です。場合によって使い分け下さい。
解説
【AEスクリプト】移動や削除で変数とのリンクが外れたプロパティを得る方法を応用して作成しました。
幸い、エクスプレッションでもプロパティ指定は番号、数字の両方でできるようなので比較的簡単に作れました。
プロパティをさかのぼって番号か名前を配列に集めていき、join()で『”).(“』を間に挟んだ文字列に変換、そして前後に『”(”』と『”)”』を付けて…といった感じです。
*具体例その2について
ちなみに、 ‘ や ” は「文字列ですよ」と表すためのもの、’\n’は改行です。エクスプレッション用文字列をスクリプト内で記述するときは、長いのでこのように書くことがあります。
” と ‘ はどちらをつかってもよいです。が、スクリプト内のエクスプレッションは文字列で表すので
〇〇.expression=’なんちゃら’;
のように、 ‘ か ” で囲って入れねばなりません。しかし、そのエクスプレッションの中にも ‘ や ” が使われている場合があります。例えばthisComp.layer(“ヌル 1”)とかですね。
『 ” で細かく囲って、 ‘ で大きく囲えば、大きく囲った間を文字列とする、あるいは逆も可』というルールがあり、またエクスプレッションではデフォルトで ” が使われるので、スクリプト内でエクスプレッションを表す文字列を記述する場合は ‘ で囲うのがおすすめです。
複数行のエクスプレッションをスクリプトに書くとき、+でつなぐ他に行末に\を付けてつなげたりもします。VScodeの置き換え機能で、aeからコピペしたエクスプレッション部分を選び『選択範囲を検索』にし、『\n』を『\\\n』にすればできるので簡単ですね。最初に ‘ 最後に ‘; を付け加えるのを忘れないようにしてください。
それすら面倒なときはエクスプレッションをfunctionで囲んで関数にしてしまい、呼び出すときに関数.toString()で文字列にして、前後の余計な「functionなんちゃら」を削る、というやり方もできます。しかしこの関数.toString()方法は、有料スクリプトなど作るときのバイナリ形式(jsxbin)保存をすると関数がネイティブコードというものになってしまい、中身を文字列として取り出せなくなります。バイナリ形式にする予定がある場合は使わないほうがよいですね。