After Effectsユーザーのための、プログラミング入門 その11 prototypeライブラリ 1行スクリプト集
今回のテーマは「1行スクリプト」昔のプログラム雑誌でたまにあったネタです。1行だけのコーディングでどれだけ出来るか競うものでなかなか面白いものですが、ちょっと企画倒れしてただの便利な関数集になっています。
1行の定義を半角255文字以内としています。まぁ昔のテキストエディタの1行の限界が8bit長だったのでそれを基準にしました。ですが、えらい読みづらいコードになってしまったので、80文字位を目安にインデントしています(1行じゃない^^;)
今回作成したスクリプトはひとつのファイル(prototypeUno.jsx)にまとめてあります。以下のリンクからダウンロード出来ます。
prototypeUno.zip
ファイル名から察することができますが、今回作った1行スクリプトは基本的にprototypeとして作成してあります。prototypeを使ったプログラミングの例として見てください。
最初はネタとして投稿するつもりでしたが、なんか意外につかえるライブラリになっていたので実用的なTips集みたいな感じになっています。
prototypeとは
まず最初にprototypeの簡単な説明です。prototypeはJavaScript独自の機能でかなり面白い仕組みで、詳細はgoogleさんで調べてもらったほうが早いと思います。ここでは簡単な使い方だけ説明します。
JavaScriptでは以下のサンプルのように適当なObjectに変数を追加することができます。
app.project.item(1).dummy = 1; alert(app.project.item(1).dummy); //OK alert(app.project.item(2).dummy); //エラー(undefined)になる app.project.item(2).dummy = 2; alert(app.project.item(2).dummy); //OKになる |
このように動的に変数が追加できるのはJavaScriptの大きな特徴です。
ただ、Objectを作成するごとに変数を追加するのは面倒なので、元となるObjectクラスに変数を追加(拡張)できる機能をprototypeで実装できます。
使い方(宣言)の方法は簡単で、下のサンプルのようになります。
CompItem.prototype.defaultFrameRate = 24; var ac = app.project.activeItem;//CompItemを選択しているとする。 alert(ac.defaultFrameRate);//ちゃんと24と表示される。 |
上のサンプルはCompItem ObjectにdefaultFrameRate変数を追加しています。
このようにprototype定義された変数は同じ型のObject全てに追加されます。
本当はもっと複雑な仕組みですが、まぁこんな感じにアバウトに捉えてた方が使いやすいです。
興味のある方は”prototype“と”__proto__“をgoogleで調べてみると面白いと思います。
追加はObjectなら何でもいいのでFunction Objectつまり関数も定義できます。
CompItem.prototype.getSize = function(){ return [this.width,this.height];} var ac = app.project.activeItem;//CompItemを選択しているとする。 alert(ac.getSize().toString()); |
prototypeで追加する変数に対して無名関数で関数を定義しています。
もちろん普通の関数も追加することができます。
function getSize() { return [this.width,this.height]; } CompItem.prototype.getSize = getSize; var ac = app.project.activeItem;//CompItemを選択しているとする。 alert(ac.getSize().toString()); |
prototyepで宣言した変数・関数は後は普通の変数・関数と同じように使えます。
注意する点として動的に同名の変数で上書きしてしまっても、その後に作成したObjectには影響を受けないって事くらいです。
下のサンプルを実行してみると何となくわかると思います。
//あらかじめダミーのコンポを二つだけ作成すること CompItem.prototype.foo = "foo"; //foo変数をfooで宣言 var comp1 = app.project.item(1);//CompItemだとする var comp2 = app.project.item(2);//CompItemだとする alert("comp1:"+comp1.foo); //fooと表示される alert("comp2:"+comp2.foo); //fooと表示される comp1.foo = "bar"; //barで上書き alert("1 comp1:"+comp1.foo); //barと表示される alert("1 comp2:"+comp2.foo); //fooと表示される delete comp1.foo; //わざと消す alert("2 comp1:"+comp1.foo); //fooと表示される。元のfooが復活してる alert("2 comp2:"+comp2.foo); //fooと表示される CompItem.prototype.foo = "bar"; //foo変数をbarでprototypeを上書き alert("3 comp1:"+comp1.foo); //barと表示される。prototypeが上書きされたから alert("3 comp2:"+comp2.foo); //barと表示される |
以上がprototypeの簡単な説明です。
1行スクリプト集(prototypeUno.jsx)について
prototypeUno.jsxは、実は僕が作っているbryfulライブラリをprototypeとして再定義したものになります。元が関数スタイルのライブラリだったのですが、prototypeスタイルにしたら異様に使いやすくなってびっくりです。
prototypeUno.jsxは一回実行すればいいので、Scripts/Startupフォルダに入れておけば起動後すぐに使うことができます。
prototypeUno.jsxが実行されたかどうかは、(app.uno != undefined)で調べることができます。
例えば使われていない平面を収集するスクリプトを普通に書けば
var fld = app.project.items.addFolder("使われていない平面"); for ( var i=1; i < app.project.numItems; i++){ var target = app.project.item(i); if ( target instanceof FootageItem){ if ( target.mainSource.color != undefined){ //平面か調べる if (target.usedIn.length <=0) target.parentFolder = fld; } } } |
となりますが、prototypeUno.jsxで拡張された機能で書くと以下のようになります。
var fld = app.project.folder("使ってない平面"); app.project.getSolid().interate( function(t){ if ( t.noneUsed()) t.parentFolder = fld; } ); |
分かりやすくするためにインデントしてますが、ほぼ1行分のコードで実装できてしまいます。
深い階層のフォルダも一発で作れます。
//深い階層のフォルダを作成。 //同名フォルダがあったらそれを返す。 var fld = app.project.folder("foo1").folder("foo2").folder("foo3"); |
選択したコンポの大きさを変える
//選択したコンポの大きさを変更 var sz = app.compSizeDialog(); if ( sz !=null){ app.beginUndo(); app.project.getSelectedComp().interate( function(cmp){ cmp.width = sz.width; cmp.height = sz.height; } ); app.endUndo(); } |
選択されたレイヤの位置をシフト(移動)するスクリプトも下のように簡単にかけます。
//選択したレイヤの位置をシフトする var shiftPos = [100,50];//この値でシフトする app.beginUndo(); function sft(v){ return [ v[0]+shiftPos[0], v[1]+shiftPos[1] ];} app.project.selectedLayers().interate( function(tLayer){ var p = tLayer.getPos(); if ( p.numKeys==0){ p.setValue(sft(p.value)); }else{ p.interate( function(pro,idx){pro.setValueAtKey(idx, sft(pro.keyValue(idx)));} ); } } ); app.endUndo(); |
ちなみに普通に書くと下のようになります。(意外と短くなった)
//選択したレイヤの位置をシフトする var shiftPos = [100,50]; function sft(v){return [ v[0]+shiftPos[0], v[1]+shiftPos[1] ];} var ai = app.project.activeItem; if ( ai instanceof CompItem){ if ( ai.selectedLayers.length>0){ app.beginUndoGroup("Pos Shift"); for ( var i=1; i<=ai.selectedLayers.length;i++){ var p = ai.layer(i).property("ADBE Transform Group").property("ADBE Position"); if ( p.numKeys==0){ p.setValue(sft(p.value)); }else{ for ( var j=1; j<=p.numKeys; j++){ p.setValueAtKey(j, sft(p.keyValue(j))); } } } app.endUndoGroup(); } } |
prototypeUno.jsxの関数リスト
◎ロード確認用
元Object | 名称 | type | 内容 |
---|---|---|---|
Application | uno | Object | version:”1.00″ ロード確認用の変数 |
◎ファイル名の処理
元Object | 名称 | type | 内容 |
---|---|---|---|
String | getParent() | function | 親フォルダのパスを取り出す。 “/c/bin/aaa.ext”から”/c/bin”を切り出す |
String | changeExt(newExt) | function | 指定した書拡張子に変更(dotを必ず入れること)空文字を入れれば拡張子の消去。 |
String | getName() | function | ファイル名のみ取り出す(拡張子付き) “/c/bin/aaa.ext”から”aaa.ext”を切り出す |
String File | getExt() | function | 拡張子のみを取り出す。 “/c/bin/aaa.ext”から”.ext”を切り出す |
String File | getNameWithoutExt() | function | 拡張子なしのファイル名を取り出す。 “/c/bin/aaa.ext”から”aaa”を切り出す |
◎Stringの拡張
元Object | 名称 | type | 内容 |
---|---|---|---|
String | replaceAll(src,dst) | function | 文字の置換。(全ての一致した部分を置換) |
String | trim() | function | 文字列の前後の空白・改行コードを取り除く |
◎改行付きの文字列操作
元Object | 名称 | type | 内容 |
---|---|---|---|
String | toLines() | function | 文字列を改行ごとに配列に変換 |
Array | toLineStr() | function | 配列を改行区切りの文字列に変換 |
◎Arrayの拡張
元Object | 名称 | type | 内容 |
---|---|---|---|
Array | indexIn(index) | function | 指定した番号が配列の要素数内であればtrueを返す。 |
Array | clear() | function | 配列をクリア(要素数を0に) |
Array | clone() | function | 配列を複製 |
Array | first() | function | 配列の先頭を取り出す |
Array | last() | function | 配列の最後を取り出す |
Array | removeAt(index) | function | 指定したインデックス番号の要素を削除 |
Array | swap(idx0,idx1) | function | 指定したインデックス番号で要素を入れ替える |
◎Collectionの配列化
元Object | 名称 | type | 内容 |
---|---|---|---|
ItemCollection LayerCollection | toArray() | function | コレクションを普通の配列に変換 |
Array | toArray() | function | 配列自身を返す |
String | toArray() | function | 文字列を1文字1文字で配列に変換 |
◎Numberの拡張
元Object | 名称 | type | 内容 |
---|---|---|---|
Number | zero3() | function | 値を先頭を0で埋めて3桁して文字列に変換。 |
◎テキストファイルの読み書き
元Object | 名称 | type | 内容 |
---|---|---|---|
File | loadText() | function | 文字列を読み込む |
File | saveText(str) | function | 文字列を書き込む |
String | save(file or path) | function | 文字列を書き込む 引数は File objectかファイルのパス文字列 |
◎interate(配列の要素全てに指定した関数を適応させる。指定する関数の引数に注意)
元Object | 名称 | type | 内容 |
---|---|---|---|
Array ItemCollection LayerCollection | interate(func(t,idx)) | function | 配列の要素全てにfnc関数を適応 |
Property | interate(func(this,idx)) | function | 配列の要素全てにfnc関数を適応 |
◎種類の識別用
種類の識別用にFootageItem/CompItem/FolderItemに以下の関数を定義する
元Object | 名称 | type | 内容 |
---|---|---|---|
FootageItem CompItem FolderItem | isSound() | function | wav等のサウンドフッテージならtrue |
FootageItem CompItem FolderItem | isSolid() | function | 平面フッテージならtrue |
FootageItem CompItem FolderItem | isStill() | function | 静止画フッテージならtrue |
FootageItem CompItem FolderItem | isSequence() | function | 動画フッテージならtrue |
FootageItem CompItem FolderItem | isComp() | function | コンポジションならtrue |
FootageItem CompItem FolderItem | isFolder() | function | フォルダーアイテムならtrue |
FootageItem CompItem FolderItem | isNotStill() | function | 秒数を持たないアイテムならtrue |
FootageItem | noneUsed() | function | フッテージアイテムが何も使われていないときはtrue |
◎Application objectの拡張
種類の識別用にFootageItem/CompItem/FolderItemに以下の関数を定義する
元Object | 名称 | type | 内容 |
---|---|---|---|
Application | versionNumber() | function | AfterEffectsのバージョンを数値で獲得 900/1000 |
Application | majorVersion() | function | AfterEffectsのバージョンを文字列で獲得 CS4/CS5 |
Application | __pushD__ | Array | pushD/popDで使用する変数 |
Application | pushD() | function | 現在のカレントディレクトリを保存 |
Application | popD() | function | 保存したカレントディレクトリを復帰 |
Application | getCurrentPath() | function | カレントティレクトリのフルパス(デコード済み) |
Application | getCurrentPathD() | function | カレントティレクトリのフルパス(デコード前) |
Application | getScriptFile() | function | 現在実行中のスクリプトファイル自身の File objectを獲得 |
Application | getScriptName() | function | 現在実行中のスクリプトファイル名を獲得(デコード済み) |
Application | getScriptNameD() | function | 現在実行中のスクリプトファイル名を獲得(デコード前) |
Application | getScriptTitle() | function | 現在実行中のスクリプトファイル名(拡張子なし)を獲得 |
Application | getScriptPath() | function | 現在実行中のスクリプトファイルの親フォルダのパスを獲得(デコード済み) |
Application | getScriptPathD() | function | 現在実行中のスクリプトファイルの親フォルダのパスを獲得(デコード前) |
Application | beginUndo() | function | ものぐさbeginUndoGroup |
Application | endUndo() | function | ものぐさendUndoGroup |
◎接続されているモニタの状態を獲得
元Object | 名称 | type | 内容 |
---|---|---|---|
Application | getScreenCount() | function | PCに接続されているモニタの数を獲得 |
Application | getMainScreenWidth() | function | プライマリーモニタの横ピクセルを獲得 |
Application | getMainScreenHeight() | function | プライマリーモニタの縦ピクセルを獲得 |
Application | getMainScreenSize() | function | プライマリーモニタのサイズを配列で獲得 |
Application | getSubScreenWidth() | function | セカンダリーモニタの横ピクセルを獲得 |
Application | getSubScreenHeight() | function | セカンダリーモニタの縦ピクセルを獲得 |
Application | getSubScreenSize() | function | セカンダリーモニタのサイズを配列で獲得 |
◎CompItemの拡張
元Object | 名称 | type | 内容 |
---|---|---|---|
CompItem | getFrame() | function | コンポの長さをフレーム数で獲得 |
CompItem | setFrame() | function | コンポの長さをフレーム数で設定 |
CompItem FootageItem | createComp() | function | コンポ・フッテージと同じ大きさ長さのコンポを作成 |
Application CompItem | compSizeDialog() | function | コンポの大きさを入力するダイアログの表示。 |
◎AVLayerの拡張
元Object | 名称 | type | 内容 |
---|---|---|---|
AVLayer | cutAtTime(time) | function | レイヤの分割 |
AVLayer | remapIsOnekey() | function | レイヤのタイムリマップを0で静止画状態に |
AVLayer | getPos() | function | Positionプロパティの獲得 |
AVLayer | getAnc() | function | Anchor Pointプロパティの獲得 |
AVLayer | getScale() | function | Scaleプロパティの獲得 |
AVLayer | getRot() | function | Rotateプロパティの獲得 |
AVLayer | getRotX() | function | Rotate Xプロパティの獲得 |
AVLayer | getRotY() | function | Rotate Yプロパティの獲得 |
AVLayer | getRotZ() | function | Rotate Zプロパティの獲得 |
AVLayer | getOpacity() | function | Opacityプロパティの獲得 |
◎Projectの拡張
元Object | 名称 | type | 内容 |
---|---|---|---|
FolderItem Project | folder(name) | function | フォルダを作成。指定した同じ名前のフォルダがあったらそれを返す。 |
◎選択の処理
元Object | 名称 | type | 内容 |
---|---|---|---|
CompItem | selectionPush() | function | レイヤの選択状態を記憶 |
CompItem | selectionPop() | function | レイヤの選択状態を復帰 |
CompItem | selectionNone() | function | レイヤの選択を全て解除 |
Project | selectionPush() | function | アイテムの選択状態を記憶 |
Project | selectionPop() | function | アイテムの選択状態を復帰 |
Project | selectionNone() | function | アイテムの選択を全て解除 |
◎アイテムの探索
元Object | 名称 | type | 内容 |
---|---|---|---|
Project | findItemByName(name) | function | プロジェクト内のアイテムを名前で探す。結果は配列で返る。 |
FolderItem | findItemByName(name) | function | フォルダ内のアイテムを名前で探す。結果は配列で返る。 |
Object | isAEItems() | function | ObjectがAfter Effectsのアイテムかどうか |
Array | getComp() | function | 配列内からCompItemを抽出 |
Array | getFootage() | function | 配列内からFootageItemを抽出 |
Array | getSolid() | function | 配列内から平面フッテージを抽出 |
◎FootageItemの拡張
元Object | 名称 | type | 内容 |
---|---|---|---|
FootageItem | useReplace(item) | function | 使用されているフッテージを使用しているレイヤ全てを指定したフッテージに置き換え 引数はAVLayer replaceSource() methodと同じ |
◎アクティブアイテムの獲得
元Object | 名称 | type | 内容 |
---|---|---|---|
Project | getActiveComp() | function | 現在アクティブなコンポを返す |
Project | getActiveFootage() | function | 現在アクティブなフッテージを返す |
Project | getSelectedComp() | function | 選択されているコンポを配列で返す。 |
Project | getSelectedFolder() | function | 選択されているフォルダアイテムを配列で返す。 |
Project | getSelectedFootage() | function | 選択されているフォルダを配列で返す。 |
Project | selectedProperties() | function | 現在選択されているプロパティを配列で返す。 |
Project | selectedLayers() | function | 現在選択されているレイヤを配列で返す。 |
Project FolderItem | getComp() | function | フォルダーアイテム内のCompItemを獲得 |
Project FolderItem | getFootage() | function | フォルダーアイテム内のFootageItemを獲得 |
Project FolderItem | getFolderItem() | function | フォルダーアイテム内のFolderItemを獲得 |
Project FolderItem | getSolid() | function | フォルダーアイテム内の平面フッテージを獲得 |
◎Propertyの拡張
元Object | 名称 | type | 内容 |
---|---|---|---|
Property | isKeyAtTime(time) | function | 指定された時間にキーフレームがあったらtrue |
Property | keyClear() | function | キーフレームを全て削除 |
Property | keyFreeze() | function | キーフレームを最初の1個のみにする |
Property | getParentLayer() | function | このプロパティのあるLayer objectを返す |
Property | keySelectedAll() | function | 全てのキーフレームを選択。引数にfalseを入れると全ての選択を解除 |
◎Window objectの拡張
元Object | 名称 | type | 内容 |
---|---|---|---|
Window | rightTop() | function | ウィンドウの表示位置を右上に設定 |
◎デバッグ用の出力コンソール
元Object | 名称 | type | 内容 |
---|---|---|---|
Application | showDebugConsole() | function | デバッグコンソールの表示 |
Application | dbPut(str) | function | デバッグコンソールに文字表示 |
Application | dbInsert(str) | function | デバッグコンソールの先頭に文字列追加 |
Application | dbWrite(str) | function | デバッグコンソールに文字列追加 |
Application | dbWriteLn(str) | function | デバッグコンソールに文字列追加。改行付き |
Application | dbClear() | function | デバッグコンソールのクリア |
Application | dbClose() | function | デバッグコンソールの消去 |
最後に
今回は「1行スクリプト」ってネタでJavaScriptのTips集的な記事にしようと思ってましたが、実際に書いてみると200文字超えがほとんどでで1行って言うのにはちょっと長すぎました。反省。ですが今回は自作のライブラリをprototypeに直したものになりますが、ネタのつもりがかなり実用的なものになってます。
今回のスクリプトをもっと洗練させれば、JavaScriptで有名なライブラリのprototype.jsのAfterEffects版が作れそうな予感がします。
最後に今回のスクリプトの著作権は僕にありますが、個人・商業での使用はフリーです。
新着記事 : After Effectsユーザーのための、プログラミング入門 その11 prototypeライブラリ 1行スクリプト集 http://t.co/h8INUy8l
新着記事 : After Effectsユーザーのための、プログラミング入門 その11 prototypeライブラリ 1行スクリプト集 http://t.co/h8INUy8l
AEPProjectに prototypeUno.jsx 1行スクリプト集の記事を投稿しました。http://t.co/Bzj4NhG7
新着記事 : After Effectsユーザーのための、プログラミング入門 その11 prototypeライブラリ 1行スクリプト集 http://t.co/h8INUy8l
新着記事 : After Effectsユーザーのための、プログラミング入門 その11 prototypeライブラリ 1行スクリプト集 http://t.co/h8INUy8l
これ入門っつーか中級なかんじがするんですが・・・・w情報処理を事前にまなんでいるなら、入門だろうね・・・・・http://t.co/dt0kfN1d
新着記事 : After Effectsユーザーのための、プログラミング入門 その11 prototypeライブラリ 1行スクリプト集 http://t.co/h8INUy8l
スーパーbryfulライブラリすっげぇ(;´Д`)bryfulさんの投稿でprototypeの意味がモワッとわかったような・・・数行コード書けるかも・・・ http://t.co/tqiRHbNd
After Effectsユーザーのための、プログラミング入門 その11 prototypeライブラリ 1行スクリプト集 http://t.co/X5wJLhDY
後で読みます After Effectsユーザーのための、プログラミング入門 その11 prototypeライブラリ 1行スクリプト集 | AEP Project: http://t.co/ScR4x1Se
「After Effectsユーザーのための、プログラミング入門 その11 prototypeライブラリ 1行スクリプト集」AEP Project http://t.co/U8iKRs9w #CS5_jp
スクリプトは経験があるけれど他の言語はさわったことがないユーザーを対象に、C#/AEのJavaScriptをメインにプログラム全般を解説する連載の第11回です。今回のテーマは「1行スクリプト」です。http://t.co/U8iKRs9w
「After Effectsユーザーのための、プログラミング入門 その11 prototypeライブラリ 1行スクリプト集」AEP Project http://t.co/U8iKRs9w #CS5_jp
スクリプトは経験があるけれど他の言語はさわったことがないユーザーを対象に、C#/AEのJavaScriptをメインにプログラム全般を解説する連載の第11回です。今回のテーマは「1行スクリプト」です。http://t.co/U8iKRs9w
「After Effectsユーザーのための、プログラミング入門 その11 prototypeライブラリ 1行スクリプト集」AEP Project http://t.co/U8iKRs9w #CS5_jp
「After Effectsユーザーのための、プログラミング入門 その11 prototypeライブラリ 1行スクリプト集」AEP Project http://t.co/U8iKRs9w #CS5_jp
「After Effectsユーザーのための、プログラミング入門 その11 prototypeライブラリ 1行スクリプト集」AEP Project http://t.co/U8iKRs9w #CS5_jp
「After Effectsユーザーのための、プログラミング入門 その11 prototypeライブラリ 1行スクリプト集」AEP Project http://t.co/U8iKRs9w #CS5_jp