Adobe JSX とは
JavaScript で Adobe 製品を操る仕組みのこと。
今回「Photoshop のレイヤーカラーラベルを変更できるスクリプト」を作ってみようと思い立ったのだが、あまり情報がない。
もとい、有用な情報があまりない。
検索すると色々出てくるんだけど「これをコピペしよう」とかが多く実際に利用できそうなスクリプトがないし資料もない。
なので、他の記事ではあまり触れられておらず苦労した部分だけ書いた。
※Adobe JSX といいつつ Photoshop についてのみ記載…
あまり他の記事に書かれていないこと
普通の JavaScript でいい
拡張子を jsx にするだけ。
上から順に実行される。
Script フォルダに入れておけば自動的に [ファイル]→[スクリプト] に表示される
Script フォルダはデフォルトであれば、ここ。
C:\Program Files\Adobe\Adobe Photoshop 2021\Presets\Scripts\
Photoshop の JSX は2種類の操作方法がある
- 一般的な DOM オブジェクトによる操作
- 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); // 人間が解る形に変換
ここで出てくる Lyr
や Ordn
といった謎の4文字についてはオフィシャルにも全ては載っていない。
全てが載っているページは↓の WaybackMachine にある
Photoshop Constants Rosetta Stone
また、そもそも Action を使った処理を人間の手で書いている人はあまりいない。
というのも、Adobe が提供している ScriptingListener というプラグインを使うと Action を JavaScript として保存できるようになるため。
必要な処理を Action として記録して Script 化して使っている人が多いのが実情。
JSX で○○するにはこうするんだよ~的なスクリプトが沢山公開されているが、変数名が foo1
, foo2
みたいな連番ぽい数字が付いているものは ScriptingListener を使って作ったもの。
全然参考にならない。
そんな訳なので実は ActionReference と ActionDescriptor についてはあまり良く理解できていない。
恐らく
- ActionReference 操作対象
- ActionDescriptor 操作に必要なプロパティなどを保存する Key-Value ストレージ
という感じかなあと思っている。
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