PhotoshopのJSXでは、app.load(File)でATNを読み込み、app.doAction(アクション名, セット名)で読み込んだアクションを再生します。ATNのファイル名と、内部に保存されたセット名・アクション名をそれぞれ確認してください。
以下は自作の練習ATNと画像コピー1枚を使う例です。同名セットが既にある場合は停止し、既存セットの削除や置き換えは行いません。Photoshop本体での読み込み・再生は未検証のため、仕事用の画像を使う前に練習用の入力と結果を照合します。
練習ATNと元サイズの画像コピーを用意する
ATNの保存・読み込み手順で、CGM-ATN-PracticeセットのResize-Width200を保存します。練習アクションは幅200pxへ変更する手順だけにし、開く・保存・閉じる操作を記録しません。架空の400×200px画像は、再生後に200×100pxとなる想定です。
ATNを保存した環境では元のセットがパネルに残っています。この例は同名セットがあると読み込み前に停止します。自作の練習セットだけを別名へ変更するか、まだそのATNを追加していない環境で試してください。仕事用のセットを削除して空きを作る手順は使いません。
元サイズの画像を開いて[イメージ]→[複製]で練習コピーを作り、元画像を閉じます。スクリプト実行時は未保存の練習コピー1枚だけを開きます。コードは開いている文書数を確認しますが、文書が練習用か、アクションに保存操作が含まれるかまでは判定しません。
ATNを選び、名前を照合して再生するコード
次のコードをUTF-8のImportAndRunAction.jsxとして保存し、[ファイル]→[スクリプト]→[参照]から実行します。初回の参照実行では、インストール先への配置やPhotoshopの再起動は必要ありません。
ファイル選択の後に、ATN内のセット名とアクション名を入力します。名前は大文字・小文字を含めて一致させます。例えばファイル名がcgm-atn-practice.atnでも、セット名はCGM-ATN-Practice、アクション名はResize-Width200です。
#target photoshop
(function () {
function trimmed(value) { return String(value).replace(/^\s+|\s+$/g, ""); }
function readSets() {
var result = [];
for (var i = 1; i <= 500; i++) {
var ref = new ActionReference();
ref.putIndex(charIDToTypeID("ASet"), i);
var desc;
try { desc = executeActionGet(ref); }
catch (endOfList) { return result; }
var name = desc.getString(charIDToTypeID("Nm "));
var count = desc.getInteger(charIDToTypeID("NmbC"));
var actions = [];
for (var j = 1; j <= count; j++) {
var actionRef = new ActionReference();
actionRef.putIndex(charIDToTypeID("Actn"), j);
actionRef.putIndex(charIDToTypeID("ASet"), i);
actions.push(executeActionGet(actionRef).getString(charIDToTypeID("Nm ")));
}
result.push({name: name, actions: actions});
}
throw new Error("More than 500 sets or unable to determine the end of the list.");
}
function matchingSets(sets, name) {
var result = [];
for (var i = 0; i < sets.length; i++) {
if (sets[i].name === name) result.push(sets[i]);
}
return result;
}
try {
if (app.documents.length !== 1) {
alert("Open just one unsaved practice copy before running this script.");
return;
}
var file = File.openDialog("Choose your own practice ATN file");
if (!file) return;
if (!file.exists || !/\.atn$/i.test(file.name)) {
alert("Choose an existing .atn file.");
return;
}
var setName = prompt("Exact set name stored inside the ATN (not the filename):", "CGM-ATN-Practice");
if (setName === null) return;
var actionName = prompt("Exact action name inside that set:", "Resize-Width200");
if (actionName === null) return;
setName = trimmed(setName); actionName = trimmed(actionName);
if (!setName || !actionName) { alert("Both names are required."); return; }
if (matchingSets(readSets(), setName).length !== 0) {
alert("This set name is already loaded. Nothing was loaded or played. Inspect your practice sets first.");
return;
}
app.load(file);
var matches = matchingSets(readSets(), setName);
if (matches.length !== 1) {
alert("Expected one matching set after loading. No action was played. The loaded set may remain in the panel.");
return;
}
var actionMatches = 0;
for (var k = 0; k < matches[0].actions.length; k++) {
if (matches[0].actions[k] === actionName) actionMatches++;
}
if (actionMatches !== 1) {
alert("Expected one exact matching action. No action was played. The loaded set remains in the panel.");
return;
}
app.doAction(actionName, setName);
alert("Playback returned without an exception. Inspect the document and output before counting it as successful.");
} catch (e) {
alert("Stopped: " + e.message + "\nThe loaded set or a partially changed practice document may remain. Inspect before saving.");
}
}());
読み込み後の状態と結果を確認する
再生から例外なしで戻ったメッセージは、画像の結果を保証するものではありません。パネルに指定のセットとアクションが追加され、練習コピーが200×100pxになったかを確認します。原本ファイルの寸法・更新日時と内容も照合し、この練習ではコピーを保存せず閉じます。
読み込み後の名前照合で停止しても、追加されたセットはパネルに残ります。コードはそれを自動で削除しません。パネルで実際の名前を確認し、必要なアクションは元サイズの新しい練習コピーで手動再生して切り分けてください。再実行すると、既に読み込んだ同名セットの確認で停止します。
| 症状 | 確認する点 |
|---|---|
| 画像がない、または複数開いている | 未保存の練習コピー1枚だけにする |
| 読み込み前に停止する | ATNの存在・拡張子・同名セット・入力した2つの名前 |
| 読み込めたが再生されない | ファイル名ではなく内部のセット名・アクション名を照合。重複名も確認 |
| 再生中にエラーが出る | 記録された手順、必要な素材・フォント・プラグイン、文書条件を確認 |
| コードをメニューに常設したい | 参照実行で確認してからスクリプトのメニュー登録へ進む |
アクション内の途中の操作が成功してからエラーになると、練習コピーだけ一部が変わっている場合があります。停止を成功件数に加えず、コピーを保存せず閉じ、元サイズから再確認します。このコードは自動ロールバックや処理ファイルの削除を実装していません。
旧コードの変更点と参照用記録
旧例は、ATNの存在確認で関数から戻っても、その後の再生を呼び出していました。また、ATNファイル名由来の正規表現に一致するセットを削除してから読み込む処理がありました。今回の例では、失敗時の後続処理を止め、入力した内部名の完全一致を確認します。
旧コードと旧配置先は経緯を確認するために残します。既存セットを削除する処理を含むため、そのまま実行するコードとして使わないでください。既存GitHubの01.jsも旧例の配布記録で、このページの新しいコードへの差し替えは行っていません。
旧コードと旧配置先(参照用・実行しない)
var atnPath = "C:\\Users\\min\\Desktop\\"
var atn = "test"
var filePath = atnPath + atn + ".atn"
$.writeln(filePath);
main(); //アクションのインポート
runAtn(); //アクションの実行
function runAtn() {
var idPly = charIDToTypeID("Ply ");
var desc12 = new ActionDescriptor();
var idnull = charIDToTypeID("null");
var ref3 = new ActionReference();
var idActn = charIDToTypeID("Actn");
ref3.putName(idActn, "glay");
var idASet = charIDToTypeID("ASet");
ref3.putName(idASet, atn);
desc12.putReference(idnull, ref3);
executeAction(idPly, desc12, DialogModes.NO);
}
function main() {
var atnFile = new File(filePath);
var rex = new RegExp(decodeURI(atnFile.name.replace(/\.[^\.]+$/, '')), "g");
if (!atnFile.exists) {
alert("ActionSetが存在しません");
return;
}
var actionList = getActionSets();
for (var d in actionList) {
if (decodeURI(actionList[d]).match(rex)) unLoadAction(actionList[d]);
}
app.load(atnFile);
var actionList = getActionSets();
var flag = false;
for (var d in actionList) {
if (decodeURI(actionList[d]).match(rex)) flag = true;
}
if (!flag) {
alert("アクションセットがロードされませんでした");
return;
}
}
function getActionSets() {
cTID = function(s) {
return app.charIDToTypeID(s);
};
var i = 1;
var sets = [];
while (true) {
var ref = new ActionReference();
ref.putIndex(cTID("ASet"), i);
var desc;
var lvl = $.level;
$.level = 0;
try {
desc = executeActionGet(ref);
} catch (e) {
break;
} finally {
$.level = lvl;
}
if (desc.hasKey(cTID("Nm "))) {
var set = {};
set.index = i;
set.name = desc.getString(cTID("Nm "));
set.toString = function() {
return this.name;
};
set.count = desc.getInteger(cTID("NmbC"));
set.actions = [];
for (var j = 1; j <= set.count; j++) {
var ref = new ActionReference();
ref.putIndex(cTID('Actn'), j);
ref.putIndex(cTID('ASet'), set.index);
var adesc = executeActionGet(ref);
var actName = adesc.getString(cTID('Nm '));
set.actions.push(actName);
}
sets.push(set);
}
i++;
}
return sets;
};
function unLoadAction(aSet) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putName(charIDToTypeID("ASet"), decodeURI(aSet));
desc.putReference(charIDToTypeID("null"), ref);
executeAction(charIDToTypeID("Dlt "), desc, DialogModes.NO);
};C:\Program Files\Adobe\Adobe Photoshop CC\Presets\Scripts手動での持ち出しはATN保存・読み込み、キーからの再生はアクションのショートカット、ATNからJSXへの変換はxtoolsによる変換記録で確認できます。この例はファイル1つの読み込みと1つのアクション再生を対象にし、フォルダー一括処理は行いません。
確認範囲と公式資料
2026年10月3日に、Adobe公開のPhotoshop JavaScript Reference 2020のload・doAction・executeActionGetと、ATNの保存・読み込みを確認しました。
ファイル取消・存在確認・名前照合・読み込み失敗後の停止と既存セットを削除しない制御は、Node.jsの模擬APIで確認しています。Photoshop実機でのATN読み込み、Action Managerによる一覧取得、アクション再生と原本保持は未検証です。実機の操作画面は今回撮影していません。
