JSON形式データをスクリプトでaeに反映するアイディア【置換テキストを表計算で管理】1の続き。
あらすじ
あらかじめ作っておいたデザイン内のテキストは、管理しやすいエクセルとかスプレッドシートで入力して、After Effectsに流し込めたら便利なの?
どうなの?
ここまでの仕様を固める
スクリプトをプログラミングするに当たり、これまで分かった仕様を整理し、ルール化します。
手法としては、書き換えたいテキストレイヤー名を表計算ソフトに一覧化し、一個右のセルに書き換え後のソーステキストを入力する。テキストレイヤー名を検索し、一致するセルがあれば該当セル内のテキストを流し込む。
After Effects内のルール
- 前提としてAfter Effects内に既にデザインされたコンポジションがある
- その中にあるテキストを表計算ソフトで管理し、スクリプトで一括書き換えする
- レイヤー名をトリガーとする
- タイムライン上の視認性を考えると置換用テキストは差別化したほうが良さそう
- ラベルカラーや通常使わなそうな特定の記号を付けるなど?
- 表計算ソフトからインポート用のテキストレイヤーを設置しておく
- 表計算ソフトのセルをコピー→テキストレイヤーにペーストするとタブ区切りテキストになることを利用する
- コンポジション「tsv」内にテキストレイヤー名「tsvLayer」を置いておく
表計算ソフト内のルール
- 該当レイヤー名を全て吸い出しておく
- レイヤー名|置換テキストの横並び2セルで1セット
となると、After Effectsから置換用テキストレイヤーの一覧抜き出しの手間・抜け漏れ防止を考えると、これもスクリプトで行えると便利だ。
まずはここまで。加えてテキストの整形など構想は広がりますが、これはオプション機能として改良していくこととします。
レイヤー名をトリガーにするので、特定のテキストレイヤー名には1セルの中身を流し込むことになる。
つまり同じテキストレイヤー名が複数あれば、同一のセル内容で書き換える。同じ意味合いのテキストレイヤーでも、書き換えたいテキストが異なる場合は末尾に連番を付けるなど、異なるレイヤー名にする。
アイディアをスクリプト化する
前回触りだけ作ってみて、実装できそうで欲しい機能も見えてきたので整理してみます。
前半の処理:tsvをセルごとに分けた風の(JSON風)配列にする
//tsvコンポジション内のtsvLayerテキストレイヤーを読み込み
function f_txtReplace(){
var TAB = String.fromCharCode(9),tsvText="";
for (i=1; i<=app.project.items.length; i++){
var itm = app.project.item(i);
if(itm.name=="tsv"){
for(var j=1;j<=itm.numLayers;j++){//コンポジション内全検索
var lyr = itm.layer(j);
if(lyr.name=="tsvLayer"){
var tsvText=lyr.property("Source Text").value.text;//tsv形式のテキスト
break;
}
}//for コンポジション内
}
}//app.project.items
var cellData=[],rowCount=0;
var brTxt=tsvText.replace(/[\r\n](?!(([^"]*"){2})*[^"]*$)/g,"<br>");//セル内改行を<br>に置換
var gyou=brTxt.split(/\r\n|\r|\n/);//改行毎にsplit
for(i=0;i<gyou.length;i++){
cellData[i] = gyou[i].split(TAB);//改行splitの次はタブでsplit
rowCount=i;
}
}
15行目までは区切り文字にするのはタブであるという設定と、tsvペースト用のレイヤーにあるソーステキスト取り込み作業です。
18行目でbrTxtにセル内改行を<br>に書き換えて代入していますが、19行目でまず改行ごとに配列を分ける(split)際に、セル内(1テキスト内)でのsplitしなくていい改行と、splitしたい改行を区別するためです。
20行目のfor文からタブ毎に区切ることでcellDataという配列内に、表計算ソフトと同じ形式(いわゆるJSON形式)を再現できました。加えて複数行のテキストも入力することがあるでしょうから、セル内で改行された複数行テキストも1つの配列にねじ込めました。
流れとしては、下記のようなタブ区切りテキストがあるとすると、
※説明用に便宜上タブを[tab]、改行を[改行]と表現しています。
キャラ名[tab]ぷん子[改行] セリフ[tab]「この一撃にすべてを賭ける!」[改行] 説明[tab]ぺやぎ県ずわぬま市に住む[改行]わからないとぷんぷんしちゃう女の子。[改行]今日はどんななるへそが待ってるのかな?
18行目のvar brTxt=tsvText.replace(/[\r\n](?!(([^”]*”){2})*[^”]*$)/g,”<br>”); で
キャラ名[tab]ぷん子[改行] セリフ[tab]「この一撃にすべてを賭ける!」[改行] 説明[tab]ぺやぎ県ずわぬま市に住む<br>わからないとぷんぷんしちゃう女の子。<br>今日はどんななるへそが待ってるのかな?
に変換し、続く19行目var gyou=brTxt.split(/\r\n|\r|\n/);で
gyou[0]="キャラ名[tab]ぷん子" gyou[1]="セリフ[tab]「この一撃にすべてを賭ける!」" gyou[2]="説明[tab]ぺやぎ県ずわぬま市に住む<br>わからないとぷんぷんしちゃう女の子。<br>今日はどんななるへそが待ってるのかな?"
と改行ごとに配列に分けます。変数.split(区切り文字)は、区切り文字で分割し配列化する関数です。結果は必ず自動的に配列になります。
最後に20行目からのfor文で今度はタブごとにsplitし、
cellData[0][0]="キャラ名"; cellData[0][1]="ぷん子"; cellData[1][0]="セリフ"; cellData[1][1]="「この一撃にすべてを賭ける!」"; cellData[2][0]="説明"; cellData[2][1]="ぺやぎ県ずわぬま市に住む<br>わからないとぷんぷんしちゃう女の子。<br>今日はどんななるへそが待ってるのかな?";
このように表計算ソフトのセル風に取り込めました。
続いてこのプログラム内にテキストを置換する処理を足していきます。
後半の処理:セルごとに区切ったテキストを該当レイヤーに流し込む
var newTxt="";
//プロジェクトウィンドウ全検索_コンポ内処理
for (i=1; i<=app.project.items.length; i++){
itm = app.project.item(i);
if(itm instanceof CompItem){// - compなら中身も全検索
for(var j=1;j<=itm.numLayers;j++){//コンポジション内全検索
lyr = itm.layer(j);
for (var row=0; row<=rowCount; row++){//行番号
for(var col=0; col<=cellData[0].length;col++){//列番号
if(lyr.name==cellData[row][col]){// レイヤー名と一致した場合
newTxt=cellData[row][col+1].replace(/^\"/g,"").replace(/\"$/g,"").replace(/<br>/g,"\r");//一致テキストの右セルが新しいテキスト
lyr.sourceText.setValue(newTxt);
}
}//列番号
}//行番号
}//for comp内全検索
}// - compなら中身も全検索
}//forプロジェクトウィンドウ全検索
After Effects内のコンポジションとレイヤーを全検索し、レイヤー名とtsvに一致するものがあれば、その一つ右のセルとして取り込んだ文言をソーステキストに置き換えてやります。
その際、14行目で<br>を通常の改行を戻すのを忘れずに。
さらにセル内で改行されたテキストは、最終的なテキストには不要な””で囲まれてまう仕様なので、冒頭の”と行末の”もそれぞれreplaceして消してやります。
※これは表計算ソフトの仕様です。テキストとしてコピペする場合、セル内での改行か、行ごとの区切りか区別するためと思われます。
完成品
これを前半のスクリプト内に入れ込んだ完成形がこちらです。
app.beginUndoGroup("テキスト置換");
f_txtReplace();
app.endUndoGroup();
//tsvコンポジション tsvLayerテキストレイヤーを読み込み
function f_txtReplace(){
var TAB = String.fromCharCode(9),tsvText="";
for (i=1; i<=app.project.items.length; i++){
var itm = app.project.item(i);
if(itm.name=="tsv"){
for(var j=1;j<=itm.numLayers;j++){//コンポジション内全検索
var lyr = itm.layer(j);
if(lyr.name=="tsvLayer"){
var tsvText=lyr.property("Source Text").value.text;//tsv形式のテキスト
break;
}
}//for コンポジション内
}
}//app.project.items
var cellData=[],rowCount=0;
var brTxt=tsvText.replace(/[\r\n](?!(([^"]*"){2})*[^"]*$)/g,"<br>");//セル内改行を<br>に置換
var gyou=brTxt.split(/\r\n|\r|\n/);//改行毎にsplit
for(i=0;i<gyou.length;i++){
cellData[i] = gyou[i].split(TAB);//改行splitの次はタブでsplit
rowCount=i;
}
var newTxt="";
//プロジェクトウィンドウ全検索_コンポ内処理
for (i=1; i<=app.project.items.length; i++){
itm = app.project.item(i);
if(itm instanceof CompItem){// - compなら中身も全検索
for(var j=1;j<=itm.numLayers;j++){//コンポジション内全検索
lyr = itm.layer(j);
for (var row=0; row<=rowCount; row++){//行番号
for(var col=0; col<=cellData[0].length;col++){//列番号
if(lyr.name==cellData[row][col]){// レイヤー名と一致した場合
newTxt=cellData[row][col+1].replace(/^\"/g,"").replace(/\"$/g,"").replace(/<br>/g,"\r");//一致テキストの右セルが新しいテキスト
lyr.sourceText.setValue(newTxt);
}
}//列番号
}//行番号
}//for comp内全検索
}// - compなら中身も全検索
}//forプロジェクトウィンドウ全検索
}
こんなところでいかがでしょうか。
この動きが確認できる、スクリプトファイルとプロジェクトファイルを下記に置いておきます。
aepとjsxがzipになっています。tsvは既に入力してあるので、スクリプトを実行するだけでとりあえずの動作チェックができます。
私はWindows使いで、Chrome上のGoogleスプレッドシートからコピペで使えました。環境によるバリデーションしてないので、遊びでお試ししてみてください。
課題(欲望)
追加したい機能を欲望のままにメモしておきます。
- リンクさせるテキストのレイヤー名を一括で取得し、表計算ソフトの準備を楽にしたい
- アルファベット大文字指定や月名を「1月→January」などいろいろ変換できると便利そう
例えば、トリガー名の末尾にハッシュタグ的に変換タイプを指定することで、元テキストをいじらずに変換させます。
レイヤー名を「名前#proper」にしておけば、表計算ソフトで「kazuaki」と入力したものが「Kazuaki」になって流し込めるとか、「私の名前は○○です」の○○だけ入力すればOKみたいな決まった形式の文章の一部だけ入力できるとか。
関数化して実装できそうな考えつく変換タイプは
- #uppercase…大文字に
- #lowercase…小文字に
- #proper…1文字目だけ大文字に(キャピタライズ)
- #00…2桁のゼロパディング
- #000…3桁のゼロパディング
- #mth…数字を英語月名に
- …数字を日本語月名に
有効なのは半角英字ですかね。
是非皆さんもプログラミングで広がるAeの世界へあれしてみてください。
出発点はこのスレッドのやりとりで、その時に面白そうと思ったのとは違うものが出来ました…。
感謝
今回の記事のきっかけになったのはTerrible Junk Show氏。
サイトはhttps://terriblejunkshow.com/
エクスプレッションやスクリプトの記事も充実してて、10年くらい前にお世話になったサイト「AE 目黒区からの刺客」作ってた人でした…。そりゃ凄いわけです。ありがとうございます。
この記事へのコメントはありません。