画像ファイルを介することなく気軽に画像データを扱いたいと開発当初より思っていて、やっと煮詰まった。
カスタムパラメータ
プロジェクト内に画像データを埋め込みたいので、エフェクトのカスタムパラメータを用いる。カスタムパラメータは、通常のパラメータと違い、UI、データ構造を自由に出来るが面倒が増える。また、スクリプトから値の取得、設定が出来ない。よって、様々なエフェクトに流用出来るような汎用性の高いものを目指す、かつ、スクリプトから加工できる機能を提供するというのを、個人的な指針としている*1。ピクセルデータをそのまま保存するのは容量が嵩むので、以前個人的にプリレンダリング用としてZPngを参考にして作ったフォーマットを流用した。そして、スクリプトから画像ファイルやクリップボードに含まれる画像データを読み込めるようにした。
@image

画像を取り扱うエフェクト群として、@image, @image_file, @images_in_folderの3種を用途に応じて用意した。@imageは上記のカスタムパラメータを用いて、エフェクト内にピクセルデータを保持するエフェクト。@image_fileは画像ファイルのパスを保持して、その画像を表示するエフェクト。@images_in_folderはフォルダのパスを保持し、そのフォルダ内に含まれる画像を表示するエフェクトである。この3つさえあれば大抵の用途に対応できると現時点では思っている。画像ファイルの読み込み自体はstb_imageに委譲しているので、stb_imageで読み込めるフォーマットは読み込める。
クリップボード
CLCL 、Pasteboard Viewerを用いてクリップボードの中を眺めると、いろいろな形式が登録されているのが分かる。そこで、登録されている形式、ファイルパス、画像の情報を取得出来るようにし、クリップボードを介したやりとりをやりやすくした。
RIFX
IllustratorはCC 2014あたりから、コピー時にクリップボードにSVGを含められるようになった。すでに@svgを作り、最低限度のSVGを扱えるようにはしてあるが、Illustratorが出力するSVGにもある程度対応したい*2。そこでまず、グラデーション周りに取り掛かることにした。
カスタムパラメータやグラデーションのようなスクリプトから値を設定出来ないパラメータに対して値を設定する方法としては、プリセットを適用するという手段がよくとられる。プリセット(.ffx)はプロジェクト(.aep)と同様、RIFX*3というファイルフォーマットが用いられている。そこで、RIFXファイルをparseしてjavascriptのオブジェクトに変換、そしてそのオブジェクトを再びバイナリデータに変換する仕組みを作った*4。こうすることで、あらかじめテンプレートとなるオブジェクトを保持しておき、必要に応じてそのオブジェクトに変更を加えバイナリに変換することで、動的にプリセットを生成できる。バイナリをテンプレートとして保持し、それに必要に応じて変更を加えるという手法が大抵使われるが、かなりわずらわしい*5ので割りかし楽になった。
@svg
グラデーションを弄ることが出来るようになったので、@svgもアップデートした。
Pseudo

RIFXを弄るツールを整備したので、ついでにPseudo Effect周りも調べることにした。調査過程でパラメータの定義を司るpardチャンクのデータ構造がPF_ParamDefであることが分かったため、Pathパラメータ*6やButtonパラメータ*7も追加できるようになった。現時点だと*8、Pseudo Effect Makerを導入する方が賢明。
メッシュワープ
メッシュワープの値をスクリプトから弄られるようにした。rows, columnsの数は頂点の数なので、面の数を表すRows, Columnsパラメータの値に1足す必要がある。
API
他のスクリプトの機能を呼び出したいなというときが時たまある。例えば、@hook_solidを導入しているならば@hook_solidライクに平面を追加したいな、といったときである。そういうことがやりやすい仕組みを整備した。
@paste_clipboard
今回の更新の集大成として、Alt(Option)+Vで、クリップボードに含まれている形式に応じて色々読み込むスクリプトを作成した。
*1:カスタムパラメータにアクセスするAPIの提供も@scriptの目的の一つではある
*2:具体的には.klass、#id程度のセレクタに対応したスタイルタグを用いた間接的なスタイルの適用及びグラデーション
*4:aepの構造はLottieのParsing AEP Filesに幾分かの解析結果が載っており大いに参考にした
*5:RIFXの仕様として、親チャンクが配下の子チャンク群のデータサイズを保持するため、子チャンクのデータを弄ると親チャンクに対して再帰的に変更を加える必要がある。
*6:ファイルパスではなくマスクパスの方
*7:押された時の処理が書けないため完全に無用
*8:そして今後も