Photoshop CC 2014: JSX Document.activeLayer の妙な挙動と対策
Photoshop CC 2014 の自動化スクリプト JSX にて、現在選択されているレイヤーを示す Document.activeLayer 周りの処理がどうもおかしな動作になるため、その現象の報告と対処法をいくつか記述します。
前知識: レイヤー選択状態 三パターン
選択されているレイヤーを元に何か自動化処理を行いたい場合、「一つもレイヤーが選択されていない場合」と「レイヤーが複数選択されている場合」を考慮して JSX を作成する必要があります。
挙動
API Documentation: Document.activeLayer
公式の API ドキュメント Document.activeLayer の項には、「The selected layer.」と書かれていますが、実際は そうではない状況の以下が発生します。
(a)レイヤーが一つも選択されていない場合、Document.activeLayer は psd 内一番上の Layer or LayerSet を返却する
(b)レイヤーが一つも選択されていない状態で Document.activeLayer に任意の Layer インスタンスを設定しても、レイヤーが選択された状態にならない(不具合?)
(c)複数レイヤーが選択されている場合、Document.activeLayer は選択されているレイヤーのうち、一番上の Layer or LayerSet を返却する
単一のレイヤーのみ選択されているかどうかを知る方法
挙動(a)により、Document.activeLayer は必ずしも「選択されているレイヤー」を返却してくれません。
「単一のレイヤーのみ選択されているかどうか」を調べるには、『「レイヤーが一つも選択されていない」or「レイヤーが複数選択されている」場合に実行するとエラーが発生する処理』を用いる事で対処します。
もっと良い方法はあるかもしれませんが、例えば、選択範囲を拡張する命令 Selection.similar メソッドがエラーチェックに利用できます。
function isSelectedSingleLayer() { var selectedSingleLayer = true; var selection = app.activeDocument.selection; try{ selection.deselect(); var x = 0; var y = 0; selection.select([[x, y], [x+1, y], [x+1, y+1], [x, y+1]]); selection.similar(0, false); }catch(error){ selectedSingleLayer = false; } selection.deselect(); return selectedSingleLayer; };
Selection.select, Selection.deselect 命令は「レイヤーが一つも選択されていない」or「レイヤーが複数選択されている」状態でも実行できます。一方、Selection.similar メソッドはエラーが発生します。(Selection.similar メソッド実行前には Selection.select メソッドを実行しないと別のエラーが発生します。)
強制的にレイヤーを一つだけ選択した状態にする方法
挙動(b)により、Document.activeLayer にどのレイヤーを設定しても、レイヤーが選択状態になってくれない状況が発生します。「単一のレイヤーのみ選択されているかどうかを知る方法」でアラートを表示して、ユーザに任意にレイヤーを選択してもらうのも良いですが、配布プラグインを作成する上では不親切になってしまう場合もあります。
対処策としまして、裏API を利用する方法があります。Photoshop ScriptListener というプラグインを用いる事で、Photoshop 内のあらゆる操作がどのような 裏API で実行されているのか調べることができます。
ScriptListener 調べでは、選択されたレイヤーを強制的に一つだけにする方法は以下となります。
function selectSingleLayer(layerName) { var idslct = charIDToTypeID("slct"); var desc = new ActionDescriptor(); var idnull = charIDToTypeID("null"); var ref = new ActionReference(); var idLyr = charIDToTypeID("Lyr "); ref.putName(idLyr,layerName); desc.putReference(idnull,ref); var idMkVs = charIDToTypeID("MkVs"); desc.putBoolean(idMkVs,false); executeAction(idslct,desc,DialogModes.NO); };
それぞれの行が何を行っているのか、API ドキュメントがないため詳しくはわかりません。Photoshop で何らかの操作をすると、一つの操作毎に上記 1ブロック程度の処理が実行されています。
不明点
以下が不明点となります。
・レイヤーが一つも選択されていない状態を知る方法
・レイヤーが複数選択されている状態を知る方法
裏API には恐らく「選択されているレイヤー数を取得する」方法がありそうです。必要に応じて調査したいと思います。
追記)
裏API に関しても、API DOC に記述されていました。
Photoshop JSX API Doc