ps工具新增
This commit is contained in:
1 parent
0a1d36d276
commit
fd5a19997e
3 files changed
+2320
No files matched your search
File renamed without changes.
@@ -0,0 +1,212 @@
|
||||
#target photoshop
|
||||
app.bringToFront();
|
||||
|
||||
// 【约束】本脚本是一次性工具:窗口只在打开期间存在,点“关闭”后即销毁。
|
||||
// 禁止任何常驻机制(#targetengine、跨次运行的窗口引用/自动关闭旧窗口等)。
|
||||
// 用非模态 palette 只是为了在窗口打开时还能点选图层(实时读取选择)。
|
||||
var cID = charIDToTypeID, sID = stringIDToTypeID, tID = typeIDToStringID;
|
||||
var definitions = [
|
||||
{label: "[bone]", tag: "bone", group: true, layer: true},
|
||||
{label: "[bone:name]", tag: "bone", value: "name", group: true, layer: true},
|
||||
{label: "[slot]", tag: "slot", group: true, layer: true},
|
||||
{label: "[slot:name]", tag: "slot", value: "name", group: true, layer: true},
|
||||
{label: "[skin]", tag: "skin", group: true, layer: true},
|
||||
{label: "[skin:name]", tag: "skin", value: "name", group: true, layer: true},
|
||||
{label: "[scale:number]", tag: "scale", value: "1", group: true, layer: true},
|
||||
{label: "[folder]", tag: "folder", group: true, layer: true},
|
||||
{label: "[folder:name]", tag: "folder", value: "name", group: true, layer: true},
|
||||
{label: "[overlay]", tag: "overlay", group: true, layer: true},
|
||||
{label: "[trim]", tag: "trim", group: true, layer: true},
|
||||
{label: "[trim:false]", tag: "trim", fixedValue: "false", group: true, layer: true},
|
||||
{label: "[mesh]", tag: "mesh", group: true, layer: true},
|
||||
{label: "[mesh:name]", tag: "mesh", value: "name", group: true, layer: true},
|
||||
{label: "[ignore]", tag: "ignore", group: true, layer: true},
|
||||
{label: "[merge]", tag: "merge", group: true, layer: false},
|
||||
{label: "[name:pattern]", tag: "name", value: "*", group: true, layer: false},
|
||||
{label: "[path:name]", tag: "path", value: "name", group: false, layer: true}
|
||||
];
|
||||
|
||||
var documentOpen = true;
|
||||
try { activeDocument; } catch (ignored) { documentOpen = false; }
|
||||
if (!documentOpen) {
|
||||
alert("请先打开一个 Photoshop 文档。");
|
||||
} else {
|
||||
showDialog();
|
||||
}
|
||||
|
||||
function showDialog () {
|
||||
// 非模态窗口:打开期间可以继续在图层面板中点选图层/组,按钮点击时实时读取选择
|
||||
var dialog = new Window("palette", "Spine导出标签");
|
||||
dialog.alignChildren = "fill";
|
||||
|
||||
// 按钮按适用范围分为三组:图层与组共用 / 仅图层可用 / 仅组可用,不再根据选择置灰
|
||||
var shared = [], layerOnly = [], groupOnly = [];
|
||||
for (var i = 0; i < definitions.length; i++) {
|
||||
var definition = definitions[i];
|
||||
if (definition.group && definition.layer) shared.push(definition);
|
||||
else if (definition.layer) layerOnly.push(definition);
|
||||
else if (definition.group) groupOnly.push(definition);
|
||||
}
|
||||
addSection(dialog, "图层与组共用", shared);
|
||||
addSection(dialog, "仅图层可用", layerOnly);
|
||||
addSection(dialog, "仅组可用", groupOnly);
|
||||
|
||||
var clearButton = dialog.add("button", undefined, "清除所有标签");
|
||||
clearButton.onClick = function () { clearAllTags(); };
|
||||
|
||||
var closeButton = dialog.add("button", undefined, "关闭");
|
||||
closeButton.alignment = "right";
|
||||
closeButton.onClick = function () {
|
||||
dialog.hide();
|
||||
dialog.close();
|
||||
};
|
||||
|
||||
dialog.center();
|
||||
dialog.show();
|
||||
dialog.active = true;
|
||||
}
|
||||
|
||||
function addSection (parent, title, list) {
|
||||
if (!list.length) return;
|
||||
var panel = parent.add("panel", undefined, title);
|
||||
panel.margins = [10,15,10,10];
|
||||
panel.orientation = "column";
|
||||
panel.alignChildren = "fill";
|
||||
for (var i = 0; i < list.length; i += 4) {
|
||||
var row = panel.add("group");
|
||||
row.alignChildren = "fill";
|
||||
for (var ii = i; ii < Math.min(i + 4, list.length); ii++) {
|
||||
var definition = list[ii];
|
||||
var button = row.add("button", undefined, definition.label);
|
||||
bindButton(button, definition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function bindButton (button, definition) {
|
||||
button.onClick = function () {
|
||||
// 每次点击时重新读取当前选中的图层/组(窗口打开期间可随时切换选择)
|
||||
var items = getSelectedItems();
|
||||
if (!items.length) {
|
||||
alert("请先在图层面板中选中一个或多个图层/组。");
|
||||
return;
|
||||
}
|
||||
var value = definition.fixedValue;
|
||||
if (definition.value) {
|
||||
value = prompt("请输入 " + definition.label + " 的值:", definition.value);
|
||||
if (value == null) return;
|
||||
value = trim(value);
|
||||
if (!value || value.indexOf("]") != -1) {
|
||||
alert(definition.label + " 必须填写值,且不能包含 ]。");
|
||||
return;
|
||||
}
|
||||
if (definition.tag == "name" && value.indexOf("*") == -1) {
|
||||
alert("[name:pattern] 必须包含星号 (*)。");
|
||||
return;
|
||||
}
|
||||
if (definition.tag == "scale" && (isNaN(Number(value)) || Number(value) <= 0)) {
|
||||
alert("[scale:number] 必须是大于 0 的数字。");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!addTag(items, definition, value)) {
|
||||
alert("当前选中的对象中没有可应用 " + definition.label + " 的目标。");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function addTag (items, definition, value) {
|
||||
var tag = "[" + definition.tag + (value != null ? ":" + value : "") + "]";
|
||||
var re = new RegExp("\\s*\\[" + definition.tag + "(?::[^\\]]+)?\\]", "ig");
|
||||
var count = 0;
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
var item = items[i];
|
||||
if ((item.isGroup && !definition.group) || (item.isLayer && !definition.layer)) continue;
|
||||
var name = trim(item.name.replace(re, ""));
|
||||
setName(item.id, (name ? name + " " : "") + tag);
|
||||
item.name = (name ? name + " " : "") + tag;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
function clearAllTags () {
|
||||
var items = getSelectedItems();
|
||||
if (!items.length) {
|
||||
alert("请先在图层面板中选中一个或多个图层/组。");
|
||||
return;
|
||||
}
|
||||
clearTags(items);
|
||||
}
|
||||
|
||||
function clearTags (items) {
|
||||
var re = /\s*\[(?:(?:bone|slot|skin|folder|mesh)(?::[^\]]+)?|(?:scale|name|path):[^\]]+|trim(?::false)?|overlay|ignore|merge)\]/ig;
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
var name = trim(items[i].name.replace(re, ""));
|
||||
setName(items[i].id, name);
|
||||
items[i].name = name;
|
||||
}
|
||||
}
|
||||
|
||||
function getSelectedItems () {
|
||||
var items = [];
|
||||
try {
|
||||
var ids = getSelectedIDs();
|
||||
for (var i = 0; i < ids.length; i++) {
|
||||
try {
|
||||
var ref = new ActionReference();
|
||||
ref.putIdentifier(cID("Lyr "), ids[i]);
|
||||
var desc = executeActionGet(ref);
|
||||
var section = tID(desc.getEnumerationValue(sID("layerSection")));
|
||||
if (section != "layerSectionEnd") items.push({
|
||||
id: ids[i],
|
||||
name: desc.getString(sID("name")),
|
||||
isGroup: section == "layerSectionStart",
|
||||
isLayer: section == "layerSectionContent"
|
||||
});
|
||||
} catch (ignored) {}
|
||||
}
|
||||
} catch (ignored) {}
|
||||
return items;
|
||||
}
|
||||
|
||||
function getSelectedIDs () {
|
||||
var ids = [], ref = new ActionReference();
|
||||
ref.putEnumerated(cID("Dcmn"), cID("Ordn"), cID("Trgt"));
|
||||
var desc = executeActionGet(ref);
|
||||
if (desc.hasKey(sID("targetLayers"))) {
|
||||
var selected = desc.getList(sID("targetLayers"));
|
||||
for (var i = 0; i < selected.count; i++) ids.push(getLayerID(selected.getReference(i).getIndex() + 1));
|
||||
}
|
||||
if (!ids.length) {
|
||||
try {
|
||||
ref = new ActionReference();
|
||||
ref.putProperty(cID("Prpr"), sID("layerID"));
|
||||
ref.putEnumerated(cID("Lyr "), cID("Ordn"), cID("Trgt"));
|
||||
ids.push(executeActionGet(ref).getInteger(sID("layerID")));
|
||||
} catch (ignored) {}
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
function getLayerID (index) {
|
||||
var ref = new ActionReference();
|
||||
ref.putProperty(cID("Prpr"), sID("layerID"));
|
||||
ref.putIndex(cID("Lyr "), index);
|
||||
return executeActionGet(ref).getInteger(sID("layerID"));
|
||||
}
|
||||
|
||||
function setName (id, name) {
|
||||
var ref = new ActionReference();
|
||||
ref.putIdentifier(cID("Lyr "), id);
|
||||
var desc = new ActionDescriptor();
|
||||
desc.putReference(cID("null"), ref);
|
||||
var layer = new ActionDescriptor();
|
||||
layer.putString(cID("Nm "), name);
|
||||
desc.putObject(cID("T "), cID("Lyr "), layer);
|
||||
executeAction(cID("setd"), desc, DialogModes.NO);
|
||||
}
|
||||
|
||||
function trim (value) {
|
||||
return value.replace(/^\s+|\s+$/g, "");
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user