Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
3
Help us understand the problem. What is going on with this article?
@pik

Adobe JSX を作って知ったこと

Adobe JSX とは

JavaScript で Adobe 製品を操る仕組みのこと。

今回「Photoshop のレイヤーカラーラベルを変更できるスクリプト」を作ってみようと思い立ったのだが、あまり情報がない。
もとい、有用な情報があまりない。
検索すると色々出てくるんだけど「これをコピペしよう」とかが多く実際に利用できそうなスクリプトがないし資料もない。
なので、他の記事ではあまり触れられておらず苦労した部分だけ書いた。
※Adobe JSX といいつつ Photoshop についてのみ記載…

あまり他の記事に書かれていないこと

普通の JavaScript でいい

拡張子を jsx にするだけ。
上から順に実行される。
Script フォルダに入れておけば自動的に [ファイル]→[スクリプト] に表示される

Script フォルダはデフォルトであれば、ここ。

C:\Program Files\Adobe\Adobe Photoshop 2021\Presets\Scripts\

Photoshop の JSX は2種類の操作方法がある

  1. 一般的な DOM オブジェクトによる操作
  2. Action をスクリプト化したもの

1番の DOM オブジェクトによる操作ができる場合は問題無い。
いつも通り DOM オブジェクトの操作で済む。
例えば、アクティブレイヤーの表示・非表示を切り替える場合は

// app はビルトインのグローバル変数でここから DOM をたどれる
app.activeDocument.activeLayer.visible = false;

こんな感じ。

問題は、DOM として提供されていないプロパティを変更する場合。

  • ActionReference オブジェクト
  • ActionDescriptor オブジェクト
  • executeAction / executeActionGet 関数

を使って Action として処理する。
これがとにかく面倒くさい。
例えば、下記のコードは現在アクティブなレイヤーのカラーラベルを取得する処理。

  // 現在の Color Label の取得
  var ref = new ActionReference(); 
  ref.putEnumerated(
    charIDToTypeID("Lyr "), // 4文字ID型式を Photoshop が理解する形に変換 Lyr = Layer
    charIDToTypeID("Ordn"), // 4文字ID型式を Photoshop が理解する形に変換 Ordn = Ordinal
    charIDToTypeID("Trgt")  // 4文字ID型式を Photoshop が理解する形に変換 Trgt = TargetEnum
  );

  var desc = executeActionGet(ref); // Action を実行して ActionDescripter を取得
  var colorID = desc.getEnumerationValue(stringIDToTypeID('color')); // color プロパティを取得
  var curColor = typeIDToStringID(colorID); // 人間が解る形に変換

ここで出てくる LyrOrdn といった謎の4文字についてはオフィシャルにも全ては載っていない。
全てが載っているページは↓の WaybackMachine にある

Photoshop Constants Rosetta Stone

また、そもそも Action を使った処理を人間の手で書いている人はあまりいない。
というのも、Adobe が提供している ScriptingListener というプラグインを使うと Action を JavaScript として保存できるようになるため。
必要な処理を Action として記録して Script 化して使っている人が多いのが実情。
JSX で○○するにはこうするんだよ~的なスクリプトが沢山公開されているが、変数名が foo1, foo2 みたいな連番ぽい数字が付いているものは ScriptingListener を使って作ったもの。
全然参考にならない。

そんな訳なので実は ActionReference と ActionDescriptor についてはあまり良く理解できていない。
恐らく

という感じかなあと思っている。

JavaScriptResource

このスクリプトの各種属性を記述しておく所。
ちなみに、Photoshop の起動時1回だけ読み込む。
変更した場合は Photoshop を再起動しないといけない。

詳しくは JavaScript Reference を。

今回指定した XML は↓こんな感じ。

/*
<javascriptresource>
  <name>色ラベルの変更 / Toggle Color Label</name>
  <about>
    Toggle Color Label
    Version 1.00
    Copyright (c) 2021 @pik.
  </about>
</javascriptresource>
*/

name, about タグだけ説明すると

name

メニューに表示されるテキストを指定するところ。

about

[ヘルプ]→[プラグインについて]で表示されるもの。
上記のコードのように途中で改行を入れればそのまま改行されて表示される。

他にも色々設定できて、メニューの Enable/Disable を状態に応じて自動的に変更できたりするらしいが、方法は解らず。

Target 宣言

↓こんな感じでターゲットを指定しておける。

#target photoshop

jsx ファイルをダブルクリックして起動するときとかに役立つ?

デバッグレベル

デバッグレベルは

  • 0: disable
  • 1: break on error
  • 2: break at beginning

の3つあるが、どれもエラーになった時適切に行番号を表示してくれるので 1, 2 を使う事はあまり無さそう。

$.level = 0; // デバッグレベルの設定

ローカライズ

一般的な JavaScript のローカライズ機構しか使えない

$.localize = true; // 自動的にローカライズ文字列を使う設定
const msg = {en:"test", ja:"テスト"}; // ロケールとテキストを持つオブジェクト
alert(msg); // ロケールに応じて自動的にテキストが選択される

一番悩んだのはここ。
Adobe が最初から提供している Script はメニューに各国の言葉が表示されている。
JavaScriptResource でメニューに表示されるテキストを指定できるが、ここを動的に変更しないといけない。
だが JavaScriptResource は動的に変更できないようだ。

Adobe が最初から提供している Script については Adobe format for localized Strings という特別な型式(ZString)を使っているらしい…が、ZString は Internal use only とあって情報が全然無い。

詳しくは↓
Global localize function

結局仕方がないので 色ラベルの変更 / Toggle Color Label と日本語と英語を並記した。

作った物

呼び出す度にカラーラベルが切り替わるスクリプト。
ショートカットを指定して呼び出すと便利かもしれない。
…でも単純に右クリックメニューからやった方が速いんじゃないかなあ…(奥さんの要望で作ったものの、奥さんはペンタブのペンのボタンを「ブラシの設定」「Ctrl+Z」に割り当ててる奇特な人なので必要だった)

ソース

ソースは無名関数型式にしているけど、その必要は全くない。
単純に必要なオブジェクトが取れなかった時に処理をやめさせたかっただけ。
(インデントが深くならないように)

一応 Gist にも同じ物を。
https://gist.github.com/freeonterminate/666d4f47b83594d82c9915f5e0098815

// Toggle Color Label
//
// ABOUT
//   Change color label.
//   None → Red → Orange → Yellow → Green 
//     → Blue → Violet → Gray → None
//
// LICENSE
//   Copyright (c) 2021 twitter:@pik
//   Released under the MIT license
//   http://opensource.org/licenses/mit-license.php
//
// HISTORY
//   2021/05/06  1.00  Release.
//

/*
<javascriptresource>
  <name>色ラベルの変更 / Toggle Color Label</name>
  <about>
    Toggle Color Label
    Version 1.00
    Copyright (c) 2021 @pik.
  </about>
</javascriptresource>
*/

#target photoshop

$.level = 0;
$.localize = true;

const msgErrBackground = {
  en: "Color labels cannot be set for the background layer", 
  ja: "背景レイヤーには色ラベルを設定できません"
};

(function(){
try 
{
  var doc = app.activeDocument;
  if (doc.activeLayer.isBackgroundLayer)
  {
    alert(msgErrBackground);
    return;
  }
} 
catch(e) 
{
  return;
}

const colors = [
  "none",
  "red" ,
  "orange",
  "yellowColor",
  "grain",
  "blue" ,
  "violet",
  "gray",
];

try
{
  // 現在のカラーラベルの取得
  var ref = new ActionReference();
  ref.putEnumerated(
    charIDToTypeID("Lyr "), // Layer
    charIDToTypeID("Ordn"), // Ordinal
    charIDToTypeID("Trgt")  // TargetEnum
  );

  var desc = executeActionGet(ref);
  var curColor = 
    typeIDToStringID(desc.getEnumerationValue(stringIDToTypeID('color')));

  // 設定するカラーラベルの取得
  var index = 0;
  var len = colors.length;
  for (var i = 0; i < colors.length; i++)
  {
    if (curColor == colors[i])
    {
      index = i + 1;
      break;
    }
  }

  if (index == len)
    index = 0;

  var newColor = colors[index];

  // カラーラベルの設定
  var descColor = new ActionDescriptor();
  descColor.putEnumerated( 
    charIDToTypeID('Clr '), // Color
    charIDToTypeID('Clr '), // Color
    stringIDToTypeID(newColor)
  );

  var target = new ActionDescriptor();
  target.putReference(charIDToTypeID('null'), ref);
  target.putObject( 
    charIDToTypeID('T   '), // To
    charIDToTypeID('Lyr '), // Layer
    descColor 
  );

  executeAction(charIDToTypeID('setd'), target, DialogModes.NO);
}
catch (e)
{
  alert(e.message);
}
})();

最後に

Adobe JSX を完全に理解するのは難しそう。
特に charID とかリファレンスないの酷すぎる。

一番参考になったのは↓このページ

特に役に立ったのが grain という色についてのところ。
知らなければ green のタイポだと思うところだった。

ちなみに完全に理解すると↓こういう感じで商売ができるっぽい

MightyPlugins.cc / MagicScripts
http://bereza.cz/ps

3
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
pik
シリアルゲームズ取締役 エンバカデロ・テクノロジーズ Delphi MVP。 Delphi で iOS / Android / Windows / macOS / Linux のアプリを作ったりしてるみたい。 たまに C#, .NET, Unity も使ってます。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
3
Help us understand the problem. What is going on with this article?