Photoshopのスクリプトでスマートオブジェクトを見分ける方法


CCからスマートオブジェクトは二種類ある

  1. 埋め込みのスマートオブジェクト

    従来のスマートオブジェクトの形式。

  2. リンクのスマートオブジェクト

    CCから追加されたスマートオブジェクト。別のPSDをリンクさせた形式のスマートオブジェクト

これらをjsxで見分ける方法がなんとなくあるんだろうなーと思っていたのですが、ドキュメントとにらめっこをしても一筋縄では行かないので、ちょっと遠回りな方法でチェックしているよーという備忘録。

スマートオブジェクトレイヤー判定

まずはそもそもレイヤーがスマートオブジェクトなのか判定しないといけない。これ自体はLayerKindを参照すればわかる。

if(layer.kind == LayerKind.SMARTOBJECT)
{
  alert("スマートオブジェクトですよ");
}

これで他のArtLayerやLayerSetとかからは見分けがつく。
ただし、このLayerKind.SMARTOBJECT判定では埋め込みもリンクも反応してしまうので、どっちの種類なのか判定するのは難しい。

埋め込み?リンク?判定

埋め込みとリンクとの見分けをするのに使えそうなのはリンク形式特有の機能が問題なく発行されるかをチェックすること。

使えそうな機能は属性パネルに出現する「コンテンツを編集」という機能。
(「コンテンツを編集」を実行すると、リンクしているPSDが別タブで開きます。)
これは埋め込みスマートオブジェクトにはない機能なので、埋め込みの場合は実行するとエラーが出るはずです。


var document = app.activeDocument;
// 調べたいレイヤーを取得する
var layer = document.layers[0];
if(layer.kind != LayerKind.SMARTOBJECT) return;

try
{
  document.activeLayer = layer;

  // 「コンテンツを編集」を実行
  var idplacedLayerEditContents = stringIDToTypeID( "placedLayerEditContents" );
  var desc3 = new ActionDescriptor();
  executeAction( idplacedLayerEditContents, desc3, DialogModes.NO );

 // 開いてしまったリンクのドキュメントを閉じておく
  app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);

  // 元のドキュメントに操作を移す
  app.activeDocument = doucment;

  alert("ここまで処理がくればlayerはリンクのスマートオブジェクト");
}
catch(e)
{
  alert("エラーが出た場合はリンクのスマートオブジェクトではない");
}

スマートオブジェクトリンクとレイヤーカンプ周りをここ最近調べているのですが、必要なAPIが用意されていなくてやりずらい....もっと充実してほしいです。。。

ActionDescriptorを使ってスマートオブジェクトを見分ける

2019/10/23 こちらの方が健全そうなやり方なので追記。ActionDescriptorを自前で書く方法です。
ActionDescriptorからは通常のAPIで取得できないパラメーターが色々取得できるのですが、SmartObjectの「link」というパラメーターもそのうちの一つです。

このlinkというパラメーターは外部リンクになっているSmartObjectにしか付いていないので、これを見て判定します。

getLinkLayerPath.jsx

function getLinkLayerPath(layer)
{
  if(layer.kind != LayerKind.SMARTOBJECT) return undefind;

  app.activeDocument.activeLayer = layer;

  try
  {
     var ref = new ActionReference();
     ref.putEnumerated(charIDToTypeID("Lyr "),charIDToTypeID("Ordn"),charIDToTypeID("Trgt"));
     var desc = executeActionGet(ref);

     var o = desc.getObjectValue(stringIDToTypeID("smartObject"));
     var link = o.getPath(stringIDToTypeID("link"));
     return link;
  }
  catch(e)
  {
    return undefined;
  }
}

指定したレイヤーがSmartObjectでかつ他のPSDとリンクしているものであれば、PSDのファイルパスが返ってきます。
ただの埋め込みSmartObjectだとundefindが返ってきますので、返り値をみてリンクされているレイヤーなのか、埋め込みなのか判定できる、というロジックです。
この方法だと、SmartObjectのドキュメントを一度開けるという手法を取らなくていいので、動作がすごく軽くなります!

ActionDescriptorとても便利でがしがし使ってしまうのですが、読めない人が多いのでどれくらい入れていくかが大変難しいですね....。