UXP for Photoshop:API概要とモーダルモードの挙動について

UXP for Photoshop:API概要とモーダルモードの挙動について

シリーズ投稿。Photoshopフィルタとしてsbsarを使う

忙しくて手を動かせないため、今回もドキュメントの確認、特にPhotoshop APIおよびモーダル動作周りについて、を行う。メソッドとか関数とかモジュールとかクラスとか表記揺れがあるので注意。

APIの種類

ファイル操作・ネットワーク処理・UIの構築など、プラグイン作成においてどのアプリケーションでも行うであろう操作がまとまったのがUXPモジュールで、現在UXPが使えるフォトショップとXDで共通。今後ほかのアプリケーションにUXPが積まれても同じものが使える。

一方アプリケーション独自の操作を行う場合、フォトショップであればレイヤー操作や画像操作などを行う機能が納められているのがフォトショップモジュールである。そのなかでも今回の制作物に利用しそうなものだけに注目してドキュメントを読んでいく。

PhotoShop API

webのAPIでは無いほう。ざっくり簡単に箇条書きに内容を記す。カッコ内は自分のコメント。

https://developer.adobe.com/photoshop/uxp/2022/ps_reference/

  • Photoshopモジュールを用いると、UXPからフォトショップ内のDOMがいじれる。
  • 同期メソッドと非同期メソッドがある。ExtendScriptを呼ぶ(結局呼ぶの?)際はすべて非同期である。
  • ただしプロパティをset・getする際は同期する。
  • appオブジェクトの下でフォトショップオブジェクトやメソッドにアクセスできる。
  • ドキュメント変更やアプリの状態変化を伴う処理はexecuteAsModal関数で囲め。
    (この関数が処理の衝突回避だけでなく、いろいろフォトショに処理を任せるポイントぽい。)
  • 複数のドキュメントに処理をすることもできる。(flattenメソッドは画像統合か?)
  • サンプルコードをみると確かにプロパティの取得は必ずしもexecuteAsModal関数で囲んでいない。
  • layer.kindが”GROUP”の場合はグループレイヤーで、layersとかparentで親子にアクセスする。
  • UXPはアクションを作れないが、削除・コピー・リネームおよび実行ができる。
    (使えそう。アクションのプロパティをいじれると最高なんだが。)
  • アクションの実行もexecuteAsModal関数で囲む。
  • まだUXPに実装されていない機能はbatchPlayを使って実現しろ。
  • batchPlayはexecuteAction似ているが、batchPlayは複数の処理をまとめて実行できる。
  • batchPlayはjsonを引数に取る。(フォトショのscriptListenerで取得した情報をjsonオブジェクトに翻訳する必要がありそう。)

複雑な処理を実行するあたって、個人的にはbatchPlayまで使いたくはない。UXP実装を待ちたい。アクションの活用はしていきたいが、動的な処理の変更には弱そうだ。batchPlayならjson書き換えればよいので、悩ましい。

と、思ったが次のドキュメントで出てきたサンプルコードを見る限り、batchPlayも意外と簡単なのかもしれない。描画色での塗りつぶしらしきコードが以下。

require('photoshop').action.batchPlay([{"_obj":"fill", "using":{"_enum":"fillContents","_value":"foregroundColor"}
}], {});

UXP Scripting in Photoshop

こちらもざっくりとまとめる。 https://developer.adobe.com/photoshop/uxp/2022/ps_reference/media/uxpscripting/

  • 単独のjsファイル実行が Photoshop 23.5からできるようになった。拡張子はpsjsにする。
  • enu File > Scripts > Browse… でpsjsを選択して実行可能。
  • アプリに psjsを ドロップでも実行可能。ドロップ場所がmacとwinで異なる。
  • psjsを実行するアクションを作る事ができる。
  • 今後は psjs ファイルをダブルクリックするだけで実行できるようになる。
  •  UXP Developer Tool でデバッグができる。
  • ExecuteAsModalなどで実行したときと同じような状況で実行される。
  • このページはそのあたりの機能が実装されるとアップデートされるよ。

プラグイン登録しなくても動かせるという事でとても良さそう。でも権限周りとかバージョン指定とかどうすんのか?そしてExecuteAsModal関数で処理を囲う必要がここではなさそうだ。

ExecuteAsModal

ページが長いけど、ざっくりざっくり。 https://developer.adobe.com/photoshop/uxp/2022/ps_reference/media/executeasmodal/

  • ExecuteAsModal はプラグインがフォトショップやUIをいじくるときに必要。
  • ExecuteAsModal により排他処理が可能になる。
  • 処理中はUIなどが非アクティブになり、処理が2秒以上続くと自動的にプログレスバーが出る。(いい仕様!)
  • ユーザーはモーダルをキャンセルできる。(キャンセル処理の実装どうすんだろ→コンテキストにキャンセルかどうかの情報が渡される。)
  • ExecuteAsModalで実行する処理は非同期にもできる。(逆に言えば同期でもいいのか。)
  • 他のプラグインがExecuteAsModal処理中にExecuteAsModal処理しようとするとエラーを投げるのでハンドリングしてね。(errobj.numberが9だとそういう意味。)
  • ExecuteAsModalの第一引数は実行関数、第二引数が辞書で、commandNameは必須、descriptor(実行関数に渡される第二引数)、interactive がインタラクティブモードかどうか。(後述)
  • 実行関数の第一引数はコンテキスト。
  • コンテキストに含む情報:モーダルをキャンセルされたか、キャンセル時に実行するonCancel関数、履歴操作に関するhostControlオブジェクト、
  • 行関数第二引数のdescriptorはexecuteAsModal関数への引数として渡された内容を持つ。unregisterAutoCloseDocument-実行中にドキュメントが閉じる際にどうするか??

キャンセル処理詳細

  • ユーザーがモーダル状態をキャンセルできるのは重要。ESCキーかキャンセルボタンでそれを行える。
  • キャンセル状態かどうかはコンテキストのisCancelledとonCancelを通じて知れる。
  • キャンセル処理がなされるとbatchPlayは例外を投げる。
  • サンプルコードはユーザーがキャンセルするまで待機するもの。JavaScriptの仕様的にawaitを使っていないとキャンセルできない。
  • 長い時間をともなう処理を行うが、awaitを使わない場合はコンテキストのisCancelledをチェックしてキャンセル処理を実装する。
  • 逆に言うとawaitを使っていればキャンセル処理を書かなくともキャンセルは実現される。ただしキャンセル例外が投げられる関係上、それをキャッチしてしまうとキャンセルが働かなくなる。

onCancel関数がなんなのかドキュメント読んだだけではわからず。

プログレスバー詳細

  • 自動で表示されるプログレスバーはコンテキストのreportProgressメソッドによって操作できる。
  • 状況を知らせるタイトルと進捗率をコントロール可能。

進捗率を提供しない場合、バーは更新されないんだろうか。まあやってみればわかるか。

インタラクティブモードについて

  • 処理中にユーザーが何か入力するなど反応が必要なものは、インタラクティブであることがPS23.3から必要になった。
  • プログレスバーが出なくなったり、その他ユーザの入力を妨げる処理が抑制される。
    • 情報をダイアログに入力する。
    • ユーザーが作業スペース上で選択したりマスクするなどの処理を行うことを待つ(?
  • プログレスバーのかわりとして、ユーザーはプラグインメニューから処理のキャンセルを行うことができる。

キャンセルがメニューからなのがわかりづらい。escキーは効かないのだろうか。

履歴操作について

  • コンテキストのhostControlプロパティによって、ヒストリー操作が可能。
  • ヒストリーがsuspended状態の間は操作の履歴が一つにまとめられる。
  • hostControl.suspendHistoryメソッドでヒストリ名を設定する。
  • hostControl.resumeHistoryメソッドでヒストリをまとめている状態を抜け出す。
  • resumeHistoryの第二引数にFalseを渡すと履歴の状態がサスペンドしたところまで戻る
    (履歴の区切りを細かくコントロールする際に使う?)
  • モーダルモードを抜けるとヒストリ状態は自動でレジュームされる。
  • モーダル処理が例外で抜けた場合、履歴はキャンセルされる。

自分が作ろうとしているものはアンドゥ対応できるのだろうか?広く配る予定はないのでできなくてもいいのだが。

Notificationsについて

  • モーダル実行中はアクション実行時と同じようにフォトショップからの通知がなくなる。
  • 通知は他のプラグインなどが受け取るもの。モーダル処理中のバッチプレイ通知が受け取れない。
  • モーダル状態が始まった、終わったは通知で知ることができる。

取り敢えずは気にしないでよさそう。

自動でドキュメントを閉じる

  • モーダルがキャンセルされるとその後はモーダルを抜けるまでスクリプトによるドキュメント操作ができない。
  • モーダルキャンセル後に、(作成したかもしれない)一時ドキュメントを削除するために、自動でそれらを閉じるよう、一時ドキュメントを登録しておく事が出来る。
  • 登録解除も可能。つまりキャンセルされずに処理が完了した際だけ新規ドキュメントを残すことが出来る。

実際の利用時のフィードバックからできたような印象を受ける機能で便利そうだ。まあ自分はまだ使わなそう。

モダールのネスト

  • executeAsModalで実行している処理の内部でexecuteAsModalを呼ぶことが出来る。
  • 全てのモーダルスコープは同じモーダルステートを共有する。つまり、入れ子のexecuteAsModalからは同じ1つのプログレスバーをコントロールする事になる。
  • ヒストリ操作も同様で、サスペンド・レジューム状態が共有される。

まとめ

やはりモーダルモードがUXPでのフォトショプラグイン開発の要だ。一旦作り終わったらこの投稿を見直して、別途振り返り投稿をしたい。するかな。

NEXT TODO

次回こそ手を動かしたい。

前の投稿

次の投稿

Previous post UXP for Photoshop:manifestの作成
Next post UXP for Photoshop:利用しそうなクラスとメソッドの確認