CEPガイド5:ツール連携

本記事はCEPスーパーメガガイドのPart 5です。
エクステンションの参考用ソースはこちら

いよいよ、カスタムパネルからホストツール側のAPIを呼ぶ話まで参りました。ちょっと詳細になるがどうぞ付き合ってください。

概要・設計

CEP 5に対応するアドビツールはそれぞれ、ツールの自動化などのためにJavascriptエンジンを実装する。しかし、これはエクステンションのパネルが実装するブラウザ環境のJSエンジンと違うもの。そのため、エクステンションとツールの連携を作るには、2つのJavascript環境をまたぐやり取りになる。

本記事では2つJS環境をパネルVM、そしてツールVMとする。

つまり、ツールの内部機能(ファイルの編集など)はツールVMのみから直接触れる。パネルVMのスクリプトから触れるには、ツールVMでスクリプトを実行させるコマンドを利用する。

そしてツールによって、ツールVMはさらに2種類ある。Flash ProはJSFLになり、それ以外のツールはExtendScript。それぞれのAPIが異なるが、呼び方と使い方は主に一緒。ちなみに、JSFLとExtendScript用スクリプトには「jsfl、jsx」の拡張子を使うことが歴史的に多いが、言語はどちらも標準Javascriptである。拡張子も任意なので「.js」を使っても問題はない。(パネル用とツール用のスクリプト間違わないように拡張子を分けることをお勧めするが。)

ツールVMでのスクリプト実行

パネルコンテンツからツールVMでスクリプトを実行するには、本シリーズのPart 3で説明したCSInterfaceオブジェクトを使う。evalScript メソッドでツール用のスクリプトをストリングとして渡す。例えばツール側からalert() を呼ぶには:

var js = "alert('ツールから')";
var cs = new CSInterface();
cs.evalScript(js);

evalScript に渡すストリングはツールVMによって実行される。そしてコールバック関数も渡すと結果も取得できる。ツールVMを学ぶため私は、パネルVMでこんなこんな関数を用意した:

window.e = function(js) {
new CSInterface().evalScript(
js, function(res) { console.log(res); }
);
}

そうするとデバッグ機能のJSコンソールを使って、簡単にツールVMで遊べる:

ツールVMでのファイル実行

しかし長いスクリプトのストリング化が面倒になるので、ファイルを丸ごとツールVMで実行することも可能。パネルの初期時に実行する場合、エクステンションのマニフェストのScriptPath タグを使う:

<Extension Id="com.fenomas.example.andytest">
<DispatchInfo>
<Resources>
<MainPath>./index.html</MainPath>
<ScriptPath>./jsx/</ScriptPath>
</Resources>

上記のようにパスを定義すると、フォルダの中身が初期時にツールVMで実行される。また、初期の後で動的にファイルを実行するAPIもある。JSFLではfl.runScript 、ExtendScriptでは$.evalFile を使う。Flashにも他のツールにも対応するエクステンションには、私はこのように外部ファイルを実行した:

var extPath = new CSInterface().getSystemPath(SystemPath.EXTENSION);
if (app=="FLPR") {
var jsflPath = extPath + "/ext/tool.jsfl";
jsflPath = encodeURI( "file://" + jsflPath );
cs.evalScript( 'fl.runScript( "' +jsflPath+ '")' );
} else {
var jsxPath = extPath + "/ext/tool.jsx";
cs.evalScript( '$.evalFile( "' +jsxPath+ '")' );
}

複雑に見えるかも知れないが、それぞれのコマンドがどのVMで実行されているかを間違わないでください:

  • new CSInterface().evalScript とはパネルVMからツールVMへストリングを渡すためのAPI
  • fl.runScript と$.evalFile とはツールVM側で実行される、外部ファイルをスクリプトとして実行するためのAPI

ツール側のAPIについて

ツールVMから各ツールのAPIを呼ぶのは簡単:

// Photoshopで新規ファイルを開く
app.documents.add(
UnitValue(550, "px"), // 幅
UnitValue(450, "px"), // 縦
72, // 解像度
"ハローワールド", // タイトル
NewDocumentMode.RGB, // カラーモード
DocumentFill.WHITE // BG色
);

しかし、どんなAPIをどうやって呼べば良いか、を探すことはそう簡単ではない。ドキュメンテーションはもちろんあるが、詳細がツールで異なるし、ドキュメンテーションで調べるより効果的な方法もあったりする。以下、私が把握して来たテクニックをまとめる。

※ ちなみに下記のツール側のAPIは、今回CEP 5にリリースによって大きく更新されたわけではない。各ツールのAPIは数年(場合によって10年以上)前からあるもんなので、検索すると色んなチュートリアルやサンプルが見つかる。

Flash・JSFLのAPIについて

JSFLの正式なドキュメンテーションはこちら。しかし、JSFL開発についての最も協力な仲間はドキュメンテーションではなく、Flashのヒストリーパネルである。JSFLのAPIを把握するには:

  1. やりたいことをFlashのUIを使って行う
  2. ウィンドウ➔ヒストリーパネルを開いてアクションを選択
  3. 右クリック➔コピー
  4. JSFLにペースト、編集
    これでほとんどの動作のAPIを簡単に把握できる。パネルメニューの表示を「パネル内のJavascript」に変更すると、APIがそのままパネルで見えてさらに便利:

ExtendScriptのAPIとツールキットについて

上記のapp.documents.add() のように、ExtendScriptにもDOM的なAPIがある。APIの一部はツールを共通するが、ほとんどの詳細がツール次第。ドキュメンテーションについて、ツールによってはまだCS版から変わっていないものもあるが、まとめるとこんな感じになる:

そしてFlashのようにAPIをヒストリーパネルから取得できないが、その変わりにExtendScript Toolkitという強力なツールがある。(インストールはCreative Cloudアプリから。)ESTKとはJSX用デバッガーのようなもので、起動しているツールの内部DOMを見たり、JSXの動的な実行などができる。ExtendScript向けの開発には絶対必須。ESTKのドキュメンテーションはツールのメニューで「ヘルプ➔Javascript Tools Guide」にあるが、簡単に言うと:

  1. ツール(Photoshopなど)を起動しておく
  2. ESTK左上のプルダウンメニューでツールを選択
  3. 右側の「データブラウザ」パネルでDOMを閲覧
  4. 左上のパネルにJSXを書いて「スクリプト実行ボタン」を押下
  5. 結果を左下のコンソールで確認

のような流れになる。

Photoshopの裏APIについて

上記のExtendScript DOMが各ツールの多くの機能に触れるが、詳細なところにアクセス出来ない機能も一部ある。しかしPhotoshopの場合に、基本的にどんなことでも出来るローレベルのAPIがDOMの裏にある。例えばローレベルAPIで新規ファイルを開くコードは:

var idMk = charIDToTypeID( "Mk  " );
var desc1 = new ActionDescriptor();
var idNw = charIDToTypeID( "Nw " );
var desc2 = new ActionDescriptor();
var idMd = charIDToTypeID( "Md " );
var idRGBM = charIDToTypeID( "RGBM" );
desc2.putClass( idMd, idRGBM );
var idWdth = charIDToTypeID( "Wdth" );
var idRlt = charIDToTypeID( "#Rlt" );
desc2.putUnitDouble( idWdth, idRlt, 500.000000 );
var idHght = charIDToTypeID( "Hght" );
var idRlt = charIDToTypeID( "#Rlt" );
desc2.putUnitDouble( idHght, idRlt, 400.000000 );
var idRslt = charIDToTypeID( "Rslt" );
var idRsl = charIDToTypeID( "#Rsl" );
desc2.putUnitDouble( idRslt, idRsl, 72.000000 );
var idpixelScaleFactor = stringIDToTypeID( "pixelScaleFactor" );
desc2.putDouble( idpixelScaleFactor, 1.000000 );
var idFl = charIDToTypeID( "Fl " );
var idFl = charIDToTypeID( "Fl " );
var idWht = charIDToTypeID( "Wht " );
desc2.putEnumerated( idFl, idFl, idWht );
var idDpth = charIDToTypeID( "Dpth" );
desc2.putInteger( idDpth, 8 );
var idprofile = stringIDToTypeID( "profile" );
desc2.putString( idprofile, "sRGB IEC61966-2.1" );
var idDcmn = charIDToTypeID( "Dcmn" );
desc1.putObject( idNw, idDcmn, desc2 );
executeAction( idMk, desc1, DialogModes.NO );

ご覧の通り、app.documents.add() にくらべて複雑。そしてこのAPIは(私が知る限り)ドキュメンテーションされていない、内部的なものなので、あまり「勉強する」ものではない。しかし使えなくはない。ScriptListenerというプラグインをインストールすれば、Photoshopでアクションを行う際にそのアクションのコマンドがデスクトップに置かれるログファイルに出力される。新規ファイルを開き方を把握するには、ScriptListenerをインストールして、新規ファイルを開いて、ログを見る感じになる。

ScriptListenerプラグインのダウンロードはPhotoshop Scriptingページにある。インストールするには、Mac版かWindows版をunzipして、Photoshopフォルダの中のPlug-insフォルダに置くだけ。

以上、私が今までに把握して来たアドビツール向けのスクリプトの書き方、呼び方についてです。次の投稿、ツール・パネル間のイベントへどうぞ!