現在のアクティブレイヤーと同じ親にある1つ上の要素を、元の選択へ追加するPhotoshop JSXです。既存の選択を先に1つへ置き換えず、隣接要素のIDとaddToSelectionで1回だけ選択を要求します。元が複数選択でも、基準にするのはapp.activeDocument.activeLayerの1要素です。
今回確認したのは標準JavaScriptの構文と模擬条件です。Photoshopでの選択・表示・実画面の撮影は未検証です。コードはレイヤーの移動・名前変更・保存を呼びませんが、選択状態は変わります。非表示、ロック、複数選択、アートボードの実際の挙動は自作の文書で確認してください。
同じ親の隣接要素を対象にする理由
DOMのlayersの先頭はレイヤーパネルの上側です。現在の要素を親のlayersからIDで探し、添字を1引いた要素を対象にします。文書直下の要素なら親はDocument、グループの子ならそのグループです。グループ自体が選ばれている場合も、その親の一覧で隣を探します。グループの子へ自動で入りません。
| 対象の条件 | この例の扱い |
|---|---|
| 同じ親の隣がグループ | グループ自体のIDを指定。内部の子は自動で複数選択しない。 |
| 隣が非表示・ロック | 候補には含める。選択可否と表示状態は実機で比較する。 |
| 同じ親の端・別の親にしか候補がない | 親の境界で停止し、別グループへ移らない。 |
| 背景・同名レイヤー | DOMの添字から候補を探し、名前やAMのitemIndex±1では指定しない。 |
| IDまたは選択一覧を読めない | 名前・AM番号へ自動で置き換えず停止する。 |
複数選択を保つための追加要求
旧コードは最初に現在のレイヤーだけを選び直すため、元の複数選択のほかの要素を失う可能性があります。新例は最初の置き換えを除去し、追加の選択要求だけを実行します。対象が既に選択済みなら追加実行も行いません。activeLayerを「最後にクリックした行」や「複数選択の最上行」とは断定しません。期待した基準かを実行前に確認してください。
同じ親の1つ上を追加する全体コード
新しい全体コードをUTF-8の.jsxとして保存し、ファイル→スクリプト→参照から実行します。旧コードへ追記せず、別ファイルとして1回実行してください。メニューへの登録は動作を確認した後に行います。
#target photoshop
(function () {
if (app.documents.length === 0) { alert("文書を開いてください。"); return; }
function validId(value) {
return typeof value === "number" && isFinite(value) && value >= 0 && Math.floor(value) === value;
}
function selectedIds() {
var key = stringIDToTypeID("targetLayersIDs");
var ref = new ActionReference();
ref.putProperty(charIDToTypeID("Prpr"), key);
ref.putEnumerated(charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
var result = executeActionGet(ref);
if (!result.hasKey(key)) { throw new Error("選択IDの一覧を取得できません。"); }
var list = result.getList(key);
var ids = [];
for (var i = 0; i < list.count; i++) {
var id = list.getReference(i).getIdentifier();
if (!validId(id)) { throw new Error("選択IDが数値の整数ではありません。"); }
ids.push(id);
}
return ids;
}
function contains(ids, id) {
for (var i = 0; i < ids.length; i++) { if (ids[i] === id) { return true; } }
return false;
}
try {
var ids = selectedIds();
if (ids.length === 0) { alert("レイヤーを1つ以上選択してください。"); return; }
var current = app.activeDocument.activeLayer;
if (!validId(current.id) || !contains(ids, current.id)) {
throw new Error("アクティブレイヤーと選択IDを照合できません。");
}
var siblings = current.parent.layers;
var position = -1;
for (var i = 0; i < siblings.length; i++) {
if (siblings[i].id === current.id) {
if (position !== -1) { throw new Error("同じIDが親の一覧に複数あります。"); }
position = i;
}
}
if (position < 0) { throw new Error("親の一覧にアクティブレイヤーがありません。"); }
var targetPosition = position - 1;
if (targetPosition < 0 || targetPosition >= siblings.length) {
alert("同じ親の上に隣接要素がありません。選択を変更しません。"); return;
}
var targetId = siblings[targetPosition].id;
if (!validId(targetId)) { throw new Error("隣接要素のIDを取得できません。"); }
if (contains(ids, targetId)) { alert("上の隣接要素は既に選択されています。"); return; }
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID("Lyr "), targetId);
var desc = new ActionDescriptor();
desc.putReference(charIDToTypeID("null"), ref);
desc.putBoolean(charIDToTypeID("MkVs"), false);
desc.putEnumerated(stringIDToTypeID("selectionModifier"),
stringIDToTypeID("selectionModifierType"), stringIDToTypeID("addToSelection"));
executeAction(charIDToTypeID("slct"), desc, DialogModes.NO);
} catch (error) {
alert("読取または選択で中断: " + error.message + "\n行: " + error.line);
}
}());
レイヤーIDと添字を混同しない
parent.layersの添字は、この親の中で位置を調べるためだけに使います。選択の指定にはputIdentifierを使い、targetIdを渡します。itemIndex、DOMの添字、layerIDは別の値です。LyrIの一覧へitemIndexをそのまま入れたり、背景の有無に合わせて独自に1を加減したりしません。
IDはこの実行中の文書で取得した値を使います。別文書へ持ち越す恒久的なIDとは扱いません。DOMのidやtargetLayersIDsが現在の版・対象で取得できなければ、選択前に中断します。2020年の公式資料だけで、すべての対象のid取得と現在の版の挙動を確認済みとはしていません。
自作PSDで確認する条件
| 入力の条件 | 模擬条件で確認した処理・実機で確かめること |
|---|---|
| 同じ親の上からA・B・CでBが基準 | Aへ追加要求 |
| 隣が非表示・同名・グループ | 名前やvisibleで候補を変更せず、そのIDを指定。実選択・表示を比較。 |
| グループの子に隣がある | その親だけの一覧で隣を指定。別の親へ飛ばない。 |
| 元が複数選択 | 一覧を保持して1回追加要求。元の全IDが残るか実機で比較。 |
| 同じ親の端・ID不明・選択不整合 | 選択要求前に停止。 |
| executeActionの例外 | 原文と行番号を表示。失敗時の状態を確認し、別対象で自動再試行しない。 |
実機では選択ID一覧とレイヤーパネルのハイライトを前後で比較し、表示・数・順序・名前も記録します。追加後に元の全IDと隣のIDがあることを確認してください。模擬検査で追加要求を確認しただけでは、Photoshopが全条件で保持した証拠にはなりません。複数選択の自動復元は含めていません。activeLayerだけを保存しても、元の全選択を復元したことにはなりません。
旧コードと過去の画面(参照用)
旧コードの初回slctは置き換え要求です。LyrIへ入れている値もitemIndexで、IDと同じ値とは保証できません。旧例を新コードへ追記しないでください。
function selectAddAboveLayer() {
var groupStartIdx = getActiveLayerIndex();
var groupEndIdx = groupStartIdx + 1; // 1つ上のレイヤーのインデックス
function getActiveLayerIndex() {
var ref = new ActionReference();
ref.putProperty(charIDToTypeID("Prpr"), charIDToTypeID("ItmI"));
ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
var res = executeActionGet(ref).getInteger(charIDToTypeID("ItmI"));
return res;
}
// 最上位のレイヤーを超えないようにチェック
if (groupEndIdx > getMaxLayerIndex()) {
alert("これ以上上にレイヤーはありません。");
return;
}
var idslct = charIDToTypeID("slct");
var desc270 = new ActionDescriptor();
var idnull = charIDToTypeID("null");
var ref210 = new ActionReference();
var idLyr = charIDToTypeID("Lyr ");
ref210.putIndex(idLyr, groupStartIdx);
desc270.putReference(idnull, ref210);
var idMkVs = charIDToTypeID("MkVs");
desc270.putBoolean(idMkVs, false);
var idLyrI = charIDToTypeID("LyrI");
var list166 = new ActionList();
list166.putInteger(groupStartIdx);
desc270.putList(idLyrI, list166);
executeAction(idslct, desc270, DialogModes.NO);
var desc271 = new ActionDescriptor();
var ref211 = new ActionReference();
ref211.putIndex(idLyr, groupEndIdx);
desc271.putReference(idnull, ref211);
var idselectionModifier = stringIDToTypeID("selectionModifier");
var idselectionModifierType = stringIDToTypeID("selectionModifierType");
var idaddToSelection = stringIDToTypeID("addToSelection");
desc271.putEnumerated(idselectionModifier, idselectionModifierType, idaddToSelection);
desc271.putBoolean(idMkVs, false);
var list167 = new ActionList();
list167.putInteger(groupStartIdx);
list167.putInteger(groupEndIdx);
desc271.putList(idLyrI, list167);
executeAction(idslct, desc271, DialogModes.NO);
}
// 最上位のレイヤーのインデックスを取得する関数
function getMaxLayerIndex() {
var ref = new ActionReference();
ref.putProperty(charIDToTypeID("Prpr"), charIDToTypeID("ItmI"));
ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Frnt"));
return executeActionGet(ref).getInteger(charIDToTypeID("ItmI"));
}
// スクリプトを実行
selectAddAboveLayer();

参照資料と確認範囲
Adobe Photoshop Scripting Guide 2020の38〜39ページ(レイヤーの並び順・グループ)、JavaScript Scripting Reference 2020のActionDescriptor、ActionList、ActionReference、Document、Layers、LayerSetを参照しています。2020年版のExtendScript資料で、今回のPhotoshop実機の検証記録ではありません。
Cutterman作者のレイヤー操作コードのtargetLayersIDsとID指定、Adobe CommunityのJJMack氏による選択追加の記録のselectionModifierを比較しました。作者の掲載例は公式の全条件保証ではなく、今回の実機成功や速度測定にも数えていません。Adobeのレイヤー選択手順で説明する行の選択と、サムネールからのピクセル選択は別です。
対象範囲が異なる選択
上への相対選択/下への相対選択はFrwr/Bckwの要求です。同じ親のDOM隣接と同じ結果を保証しません。名前から選ぶ場合は階層を含む名前選択を参照してください。
旧配布と関連する手順
旧配布はGitHubの元コードに残しています。公開フォルダーの01.jsは今回の新しい例へ更新していません。実行する場合は、このページの新しい全体コードを別の.jsxとして保存してください。





