AfterEffectsスクリプトの走り書き

# 走り書きって？
----

仕事で手の空いている時、デザイナーからAfterEffects(以後AE)スクリプト作成のお願いが来る。その度に同じこと調べている気がするのでメモを残します。メモ書きなので動作保証は無いです。随時更新予定。
以下の参考サイトにお世話になりました。細かい仕様等は参考サイトの方で確認して下さい。

[参考サイト](http://aejsx.hiroshisaito.net/home)

## JavaScriptコンソールに出力したい
$(ダラー) Objectを使う

```js
$.writeln("hell! oh! world!");
```

## ダイアログをポップアップしたい
JavaScriptと同じ。

```js
alert("I am a pen.");
```

## オブジェクトをJSONに変換したい
JavaScriptと同じ。しかし、CS6の時点ではJSONオブジェクトは使えないのでtoSourceでやる。もしくは自前で実装。

```js
var jsonString = obj.toSource();
```

自前のクラスにフレーム毎のレイヤープロパティ詰め込んでJSONにしてファイルに保存すると色々と夢が広がる。

## 今開いているプロジェクトにアクセスしたい
全てはApplication Objectから始まる。エクスプレッションではappで定義にされているので、以下の様な感じ。

```js
var prj = app.project;
```

## AEで選択されているオブジェクトにアクセスしたい
Project Objectのアトリビュートで取得可能。

```js
var activeItem = app.project.activeItem;
```

プロジェクトウィンドウ内限定ならselectionで取得

```js
var activeItem = app.project.selection;
```

## レイヤーにアクセスしたい
例えば選択されているコンポジションのレイヤーにアクセスする場合。

```js
var compItem = app.project.activeItem;
//アクセスする前に選択されているのがコンポジションか確認
if (compItem instanceof CompItem) {
    var layers = compItem.layers;
}
```

## フレームから時間、時間からフレームに変換したい
基本的に時間で管理されているが、フレームで処理したい時も多々ある。こんな感じ。

```js
var compItem = app.project.activeItem;
if (compItem instanceof CompItem) {
    //時間からフレームへ変換
    var frmFromTime = timeToCurrentFormat(4.0, compItem.frameRate, ture);
    //フレームから時間へ変換
    var timeFromFrame = currentFormatToTime(15, compItem.frameRate, ture);
}
```

## レイヤーマーカーにアクセスして、マーカー出現時間を知りたい
結構面倒。コンポ内の全レイヤーのマーカープロパティをデュレーション分トレースしてみたが、もっと上手いやり方がありそう。

```js
//とりあえずアクティブなアイテムを取得
var compItem = app.project.activeItem;
//型チェック
if (compItem instanceof CompItem) {
    //レイヤーオブジェクトのコレクションを取得
    var layers = compItem.layers;
    //コレクションサイズ分処理
    for (var i = 1; i <= layers.length; i++) {
        //トレース開始フレームを算出(必要ならinPointを加算する)
        var frmStart = timeToCurrentFormat(layers[i].startTime, 
                                           compItem.frameRate, true);
        //トレース範囲をデュレーションから求める
        var frmDuration = timeToCurrentFormat(layers[i].outPoint, 
                                              compItem.frameRate, true);
        //フレーム毎に解析
        for (var t = 1; t <= frmDuration; t++) {
            //フレーム数を秒に変換
            var time = currentFormatToTime(t, compItem.frameRate, true);
            //マーカープロパティを処理（ネストしたコンポの先は見ない事にする）
            var markerProp = layers[i].marker;
            //キーフレームがあるか確認（マーカー打つとキーフレームとして追加されるっぽい）
            if (markerProp.isTimeVarying) {
                //現在のフレームから最寄りのキーインデックスを取得
                var nearestKeyIndex = markerProp.nearestKeyIndex(time);
                //最寄りのキーの発生時間が現在のフレームと一致している時だけ処理する
                if (markerProp.keyTime(nearestKeyIndex) == time) {
                    //Marker Value Objectを取得
                    var closestMarkerFromTime = markerProp.valueAtTime(time, true);
                    if (closestMarkerFromTime.comment) {
                        //確認のためにフレーム数とコメントを出力してみる
                        $.writeln(layers[i].name + ":" + 
                                  t + ":" + closestMarkerFromTime.comment);
                    }
                }
            }
        }
    }
}
```
これでタイムラインで打ったレイヤーマーカーの位置（時間）がとりあえず求まる。

## ファイルを書き出したい
文字コードを指定しないと、システムのデフォルト文字コードで書き出される模様。

```js
var file = new File("ファイルパス");
file.encoding = "UTF-8";
file.open("w")
file.write("書き出す文字列");
file.close();
```