Photoshop Scriptコード
Scripting Listenerで取得したコードやScriptUIコードを載せています。
セレクトレイヤーダイアログ
概要
指定ドキュメントのグループとレイヤーをツリー表示します。
ツリーアイテムにチェックを入れ、OKボタンを押すとチェックされたレイヤーオブジェクトを配列で返します。
検索窓に文字を入力すると、絞り込み表示(部分一致)になります。ただしグループ配下のレイヤーがマッチした場合、先祖グループも表示されます。
コード
function main() {
if (!documents.length) {
alert('Document not found');
return;
}
var doc = app.activeDocument;
var result = selectLayerDialog(doc);
if (!result || !result.length) {
return;
}
alert(result.join('\n'));
}
/**
* レイヤー一覧ダイアログを表示し、チェックのついたレイヤーオブジェクトを
* 配列で返す
* @param {Document} doc - 表示するレイヤー一覧の対象ドキュメント
* @return {?Array.<ArtLayer|LayerSet>} - チェックのついたレイヤー群。
* OKボタン以外でダイアログを閉じた場合はnull
*/
function selectLayerDialog(doc) {
// # dialog
// ## list item
var List = {
folderIconStr:
'\u0089PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00\f\x00\x00' +
'\x00\n\b\x06\x00\x00\x00\u0080,\u00BF\u00FA\x00\x00\x00' +
'\x19tEXtSoftware\x00Adobe ImageReadyq\u00C9e<\x00\x00' +
'\x00YIDATx\u00DAbTRR\u00FA\u00FF\u00F9\u00F3g\x06\x18\u00E0' +
'\u00E7\u00E7g8\u00B7u\x1A#\x03\x0E\u00C0\u00E2\u00EB\u00EB' +
'\u00CB`oo\x0F\x17\u00D8\u00B9s\'\x03>\u00C0\u0082\u00AC\x18' +
'\x04@|e\u009B\u00E8\u00FF\u00B840._\u00BE\u00FC?\x03\t\u0080' +
'\u00E5\u00F7\u00EF\u00DF\f\u0083L\u00C3\u009F?\x7Fhl\u0083' +
'\u008A\u008A\nI\x1A\x00\x02\f\x00\u0091E\x1F\u00C2\u00E8{7' +
'\u00B1\x00\x00\x00\x00IEND\u00AEB`\u0082',
root: doc,
layerList: null,
currentLayerList: null,
/**
* ドキュメントのレイヤーを再帰でたどり、検索文字列にマッチする
* レイヤーをダイアログ内ツリーに追加する
* @param {TreeView} treeObj - ダイアログ内ツリー
* @param {string} [text=''] - 検索文字列
*/
setList: function (treeObj, text) {
var isLayer = function (layerObj) {
var typename = layerObj.typename;
return typename == 'ArtLayer' || typename == 'Layer';
};
/**
* レイヤーセットを走査し、リストオブジェクトを取得する
* @param {Array.<Object>|LayerSet|Document} layerObj -
* ドキュメント、レイヤーセット、もしくはそれらと一部
* 共通するキーを持つオブジェクトを格納した配列
* @param {ListItem|TreeView} listObj -
* ダイアログ内ツリーのアイテム要素
* @param {Array.<Object>} layerList -
* レイヤーセットと一部共通するキーを持ったオブジェクト
* を格納した配列
* @return {Array.<Object>} -
* レイヤーセットと一部共通するキーを持ったオブジェクト
* を格納した配列
*/
var getLayerList = function (layerObj, listObj, layerList) {
var layers = layerObj.layers;
var layer;
for (var i = 0, len = layers.length; i < len; i++) {
layer = layers[i];
layerList = layerList.concat(setItem(layer, listObj));
}
return layerList;
};
/**
* ダイアログ内ツリーに、検索文字列にマッチする
* レイヤー(セット)名を追加し、対象のレイヤーを
* オブジェクトに格納し配列で返す
* @param {Array.<Object>|LayerSet} layerObj -
* レイヤーセットもしくは一部共通するキーを持つ
* オブジェクトを格納した配列
* @param {ListItem} listObj -
* ダイアログ内ツリーのアイテム要素
* @return {Array.<Object>} -
* レイヤーセットと一部共通するキーを持ったオブジェクト
* を格納した配列
*/
var setItem = function (layerObj, listObj) {
var parent = layerObj.parent;
var itemList;
if (parent == root) {
itemList = listObj;
}
else {
itemList = listObj.items[listObj.items.length - 1];
}
var name = layerObj.name;
var isMatching = (name.indexOf(searchText) != -1);
var item;
if (isLayer(layerObj)) {
if (!isMatching) {
return [];
}
item = itemList.add('item', name);
item.checked = false;
return [{
'orig': layerObj.orig || layerObj,
'parent': parent,
'typename': layerObj.typename,
'name': name,
'layers': []
}];
}
item = itemList.add('node', layerObj.name);
item.expanded = true; // show children
item.checked = false;
//item.image = folderIconStr; // 520 err (first several times)
var layerList = getLayerList(layerObj, itemList, []);
if (isMatching || layerList.length) {
return [{
'orig': layerObj.orig || layerObj,
'parent': parent,
'typename': layerObj.typename,
'name': name,
'layers': layerList
}];
}
itemList.remove(item); // no match and empty node
return [];
};
var folderIconStr = this.folderIconStr;
var root = this.root;
var layerObj = this.layerList || root;
var searchText = (text == null) ? '' : text;
var layerList = getLayerList(layerObj, treeObj, []);
var currentLayerList = {'layers': layerList};
this.layerList = this.layerList || currentLayerList;
this.currentLayerList = currentLayerList;
},
/**
* ダイアログ内ツリーのアイテムを走査し、チェックのついた
* アイテムに該当するレイヤーを配列で返す
* @param {TreeView} treeObj - ダイアログ内ツリー
* @return {Array.<Layer|LayerSet>} - レイヤーオブジェクト
*/
getCheckedLayer: function (treeObj) {
var getLayerList = function (layerObj, listObj, layerList) {
var layers = layerObj.layers;
var items = listObj.items;
var layer, item;
for (var i = 0, len = layers.length; i < len; i++) {
layer = layers[i];
item = items[i];
layerList = layerList.concat(setLayerObj(layer, item));
}
return layerList;
};
var setLayerObj = function (layerObj, listObj) {
var layers = listObj.checked ? [layerObj.orig] : [];
if (listObj.type == 'item') {
return layers;
}
return getLayerList(layerObj, listObj, layers);
};
var layerObj = this.currentLayerList;
return getLayerList(layerObj, treeObj, []);
}
};
// ## dialog
var resource = 'dialog { \
text: "select layer", \
alignChildren: "fill", \
groupFilter: Group { \
stSearch: StaticText { \
text: "Search:", \
}, \
etSearch: EditText { \
active: true, \
alignment: ["fill", "left"], \
}, \
}, \
lstLayer: TreeView { \
minimumSize: [150, 200], \
}, \
groupBtn: Group { \
btnOk: Button { \
text: "OK", \
properties: { \
name: "ok", \
}, \
}, \
btnCancel: Button { \
text: "Cancel", \
properties: { \
name: "cancel", \
}, \
}, \
}, \
}';
var dialog = new Window(resource);
var list = dialog.lstLayer;
List.setList(list);
// # event
// ## EditText event
dialog.groupFilter.etSearch.addEventListener('changing', function (ev) {
list.removeAll();
List.setList(list, this.text);
});
// ## ListBox event
/**
* リストをクリックした際、チェックのtrue/falseを切り替える
* @param {TreeView} list - ダイアログ内リスト
*/
var toggleCheck = function (list) {
var selection = list.selection;
if (selection == null) {
return;
}
selection.checked = !selection.checked;
};
// keydown:
// space: expand/collapse a node in a TreeView
// enter: click button event (all Control)
list.addEventListener('keydown', function (ev) {
var keyName = ev.keyName;
//if (keyName.toUpperCase() != 'SPACE') {
if (keyName.toUpperCase() == 'ENTER') {
return;
}
toggleCheck(list);
});
list.addEventListener('click', function (ev) {
toggleCheck(list);
});
// ## Button event
var layerList = [];
// ok
dialog.groupBtn.btnOk.addEventListener('click', function (ev) {
layerList = List.getCheckedLayer(list);
dialog.close(1);
});
// cancel
dialog.groupBtn.btnCancel.addEventListener('click', function (ev) {
dialog.close();
});
if (dialog.show() == 1) {
return layerList;
}
return null;
}
main();
補足
- 処理が重いため、レイヤーやレイヤーセット数が多いドキュメントで実行すると、ダイアログ表示まで時間がかかります。
-
アイコン画像を使用した場合、最初の何回かに520エラーが出ることがあるため、コメントアウトしています。
繰り返し実行することで動作するようになります。
確認バージョン
- CS6
- CS2では動作しません