216 lines
7.2 KiB
React
216 lines
7.2 KiB
React
#target photoshop
|
||
|
||
/*
|
||
Photoshop Bake Layer Style 1.5 (PS 2026 兼容版)
|
||
|
||
功能:
|
||
1. 校验:当前是否选中了图层;
|
||
2. 校验:当前图层是否包含可转换的图层样式;
|
||
3. 显示确认窗口;
|
||
4. 确认后复制当前图层作为工作副本;
|
||
5. 隐藏原图层,将其保留为备份;
|
||
6. 在工作副本上执行"图层 > 图层样式 > 创建图层";
|
||
7. 若命令失败,自动回滚到脚本执行前的状态。
|
||
*/
|
||
|
||
(function () {
|
||
var DIALOG_TITLE = "创建图层样式";
|
||
var DIALOG_MESSAGE = "是否烘焙图层样式到单独图层?";
|
||
|
||
if (app.documents.length === 0) {
|
||
alert("请先打开文档并选择一个带有图层样式的图层。", DIALOG_TITLE, true);
|
||
return;
|
||
}
|
||
|
||
// ========== 校验 1:当前是否选中了图层 ==========
|
||
function hasSelectedLayer() {
|
||
try {
|
||
var ref = new ActionReference();
|
||
ref.putProperty(stringIDToTypeID("property"), stringIDToTypeID("targetLayers"));
|
||
ref.putEnumerated(stringIDToTypeID("document"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
|
||
var desc = executeActionGet(ref);
|
||
if (desc.hasKey(stringIDToTypeID("targetLayers"))) {
|
||
var list = desc.getList(stringIDToTypeID("targetLayers"));
|
||
return list.count > 0;
|
||
}
|
||
return false;
|
||
} catch (e) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// ========== 校验 2:当前图层是否包含图层样式 ==========
|
||
function hasLayerStyle() {
|
||
try {
|
||
var ref = new ActionReference();
|
||
ref.putProperty(stringIDToTypeID("property"), stringIDToTypeID("layerEffects"));
|
||
ref.putEnumerated(stringIDToTypeID("layer"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
|
||
var desc = executeActionGet(ref);
|
||
|
||
if (!desc.hasKey(stringIDToTypeID("layerEffects"))) {
|
||
return false;
|
||
}
|
||
|
||
// layerEffects 键存在不代表有样式,需检查内部是否有实际效果
|
||
var fxDesc = desc.getObjectValue(stringIDToTypeID("layerEffects"));
|
||
var effectKeys = [
|
||
"dropShadow",
|
||
"innerShadow",
|
||
"outerGlow",
|
||
"innerGlow",
|
||
"bevelEmboss",
|
||
"chromeFX",
|
||
"solidFill",
|
||
"gradientFill",
|
||
"patternFill",
|
||
"frameFX",
|
||
"frameFXStyle"
|
||
];
|
||
for (var i = 0; i < effectKeys.length; i++) {
|
||
if (fxDesc.hasKey(stringIDToTypeID(effectKeys[i]))) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
} catch (e) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// ========== 执行前置校验(缺一不可) ==========
|
||
if (!hasSelectedLayer()) {
|
||
alert("当前未选中任何图层,请先选择一个图层后再执行。", DIALOG_TITLE, true);
|
||
return;
|
||
}
|
||
|
||
if (!hasLayerStyle()) {
|
||
alert("当前图层没有图层样式,无法烘焙。\n请先为图层添加样式(如投影、描边、外发光等)。", DIALOG_TITLE, true);
|
||
return;
|
||
}
|
||
|
||
// ========== 确认对话框 ==========
|
||
var dialog = new Window("dialog", DIALOG_TITLE);
|
||
dialog.orientation = "column";
|
||
dialog.alignChildren = ["fill", "center"];
|
||
dialog.spacing = 16;
|
||
dialog.margins = 20;
|
||
|
||
var message = dialog.add("statictext", undefined, DIALOG_MESSAGE);
|
||
message.alignment = "center";
|
||
|
||
var buttonGroup = dialog.add("group");
|
||
buttonGroup.orientation = "row";
|
||
buttonGroup.alignment = "right";
|
||
buttonGroup.spacing = 10;
|
||
|
||
buttonGroup.add("button", undefined, "取消", { name: "cancel" });
|
||
var confirmButton = buttonGroup.add(
|
||
"button",
|
||
undefined,
|
||
"确认",
|
||
{ name: "ok" }
|
||
);
|
||
dialog.defaultElement = confirmButton;
|
||
|
||
dialog.center();
|
||
|
||
if (dialog.show() !== 1) {
|
||
return;
|
||
}
|
||
|
||
// ========== 核心执行逻辑(已验证可运行) ==========
|
||
var documentReference = app.activeDocument;
|
||
var originalLayer = documentReference.activeLayer;
|
||
var originalName = originalLayer.name;
|
||
var initialHistoryState = documentReference.activeHistoryState;
|
||
|
||
try {
|
||
var workingLayer = originalLayer.duplicate();
|
||
originalLayer.visible = false;
|
||
|
||
workingLayer.name = originalName + "_烘焙";
|
||
workingLayer.visible = true;
|
||
selectLayerExclusively(documentReference, workingLayer);
|
||
|
||
createLayersFromLayerStyle();
|
||
} catch (error) {
|
||
try {
|
||
documentReference.activeHistoryState = initialHistoryState;
|
||
} catch (rollbackError) {
|
||
try {
|
||
originalLayer.visible = true;
|
||
documentReference.activeLayer = originalLayer;
|
||
} catch (restoreError) {
|
||
// 保留最初的 Photoshop 错误信息。
|
||
}
|
||
}
|
||
|
||
var details = error.message;
|
||
if (error.number !== undefined) {
|
||
details += "\n错误编号:" + error.number;
|
||
}
|
||
if (error.line !== undefined) {
|
||
details += "\n脚本行号:" + error.line;
|
||
}
|
||
|
||
alert(
|
||
"创建图层样式失败。\n\n" +
|
||
details +
|
||
"\n\n请确认当前图层包含可转换的图层样式。",
|
||
DIALOG_TITLE,
|
||
true
|
||
);
|
||
}
|
||
|
||
function selectLayerExclusively(documentReference, layerReference) {
|
||
try {
|
||
var descriptor = new ActionDescriptor();
|
||
var reference = new ActionReference();
|
||
reference.putIdentifier(
|
||
stringIDToTypeID("layer"),
|
||
layerReference.id
|
||
);
|
||
descriptor.putReference(
|
||
stringIDToTypeID("null"),
|
||
reference
|
||
);
|
||
descriptor.putBoolean(
|
||
stringIDToTypeID("makeVisible"),
|
||
false
|
||
);
|
||
executeAction(
|
||
stringIDToTypeID("select"),
|
||
descriptor,
|
||
DialogModes.NO
|
||
);
|
||
} catch (selectError) {
|
||
documentReference.activeLayer = layerReference;
|
||
}
|
||
}
|
||
|
||
function createLayersFromLayerStyle() {
|
||
// 使用 ScriptingListener 录制的标准代码:
|
||
// 用 Mk (Make) 命令,将当前图层的 Lefx (Layer Effects) 属性创建为新图层。
|
||
var idMk = charIDToTypeID("Mk ");
|
||
var desc = new ActionDescriptor();
|
||
|
||
var idnull = charIDToTypeID("null");
|
||
var ref1 = new ActionReference();
|
||
var idLyr = charIDToTypeID("Lyr ");
|
||
ref1.putClass(idLyr);
|
||
desc.putReference(idnull, ref1);
|
||
|
||
var idUsng = charIDToTypeID("Usng");
|
||
var ref2 = new ActionReference();
|
||
var idPrpr = charIDToTypeID("Prpr");
|
||
var idLefx = charIDToTypeID("Lefx");
|
||
ref2.putProperty(idPrpr, idLefx);
|
||
var idLyr2 = charIDToTypeID("Lyr ");
|
||
var idOrdn = charIDToTypeID("Ordn");
|
||
var idTrgt = charIDToTypeID("Trgt");
|
||
ref2.putEnumerated(idLyr2, idOrdn, idTrgt);
|
||
desc.putReference(idUsng, ref2);
|
||
|
||
executeAction(idMk, desc, DialogModes.NO);
|
||
}
|
||
})(); |