如何在具有已知名称的其他图层组内裁剪和导出特定图层组?
How do I crop and export specific group layers inside other group layers with a known name?
第一次post来这里!如果此 post 缺少信息,或者有碍观瞻,我事先表示歉意!
所以,我有一堆层,结构有点像这样的例子:
+ graphics (group, unique)
+ - + Figure_A (group, unique)
+ - + - + Figure_A_arm (group, unique)
+ - + - + - + Figure_A_arm_Variation1 (group, unique)
+ - + - + - + - + frame1_arm (group, not unique)
+ - + - + - + - + - + FigureGraphic (linked layer, not unique, has a mask)
+ - + - + - + - + frame2_arm (group, not unique)
+ - + - + - + - + - + FigureGraphic (linked layer, not unique, has a mask)
+ - + - + - + - + frame2_arm (group, not unique)
+ - + - + - + - + - + FigureGraphic (linked layer, not unique, has a mask)
(unique/notunique表示图层名称是否唯一)
我正在尝试获取组层次结构中最新的像素,文档在自动导出之前被裁剪。主要问题是,有很多功能我无法弄清楚,即使在不停地戳了两个星期之后。我在脚本中挖掘了很多片段,但它变得一团糟,无法正常工作。
我在我想做的事情中包含了一个伪代码。理想情况下,我会编写其中编写的函数,但在谷歌搜索两周后,我无法弄清楚其中的很多内容。 Photoshop 脚本中的很多功能看起来很晦涩,我根本想不通...
我一直在通过从这些地方获取代码片段来编写函数:
导出为 PNG:Photoshop CS6 Export Nested Layers to PNG?
Select 所有子图层:http://www.joonas.me/posts/2018/01/30/select-child-layers-photoshop-script/
获取 selected 图层 ID:https://forums.adobe.com/thread/2256708
Select 图层按 ID:https://forums.adobe.com/thread/2140075
我一直在尝试,但我发现很难实现它们来做我需要的事情,有时我会收到错误或变量变成 'undefined',从而触发错误。
// Here's some 'pseudocode' with how I'm trying to make it work
cropAndSave("Figure_A_arm_Variation1");
cropAndSave("Figure_A_arm_Variation2");
cropAndSave("Figure_A_arm_Variation3");
cropAndSave("Figure_A_leg_Variation1");
cropAndSave("Figure_A_leg_Variation2");
cropAndSave("Figure_A_leg_Variation3");
cropAndSave("Figure_B_arm_Variation1");
cropAndSave("Figure_B_arm_Variation2");
cropAndSave("Figure_B_arm_Variation3");
//etc
function cropAndSave(nameOfGroup)
{
//nameOfGroup is the group layer we are looking for
//Duplicate the document so we don't mess with the original
var workingDoc = app.activeDocument.duplicate();
// Path we want to export to
var path="C:/test/"+nameOfGroup+"/";
// Look up for this group layer in the document
setActiveLayerSet(nameOfGroup);
// Make a list (array?) with the ids of each layer set/group inside nameOfGroup
// This shouldn't include anything inside each group, only the direct groups inside nameOfGroup
var listOfLayers = getListOfChildrenObjects();
// Loop the process for each sub-object
for( var i = 0; i < listOfLayers.length ; i++ )
{
var name = getLayerNameById(listOfLayers.i); //I don't know if this is the correct way to ask for the i element of a list
var bounds = []; //We'll be using this for the cropping
if(groupName=="Figure_A_arm_Variation1") //Checking which set we're doing
{
if(name=="frame1_arm") bounds = [1px, 2px, 3px, 4px]; //just a test value
else if(name=="frame2_arm") bounds = [5px, 6px, 7px, 8px]; //just a test value
else if(name=="frame3_arm") bounds = [9px, 10px, 11px, 12px]; //just a test value
else if(name=="frame1_leg") bounds = [13px, 14px, 15px, 16px]; //just a test value
// and so on
}
else if(groupName=="Figure_B_arm_Variation2") //one of the many possible groups
{
if(name=="frame1_arm") bounds = [17px, 18px, 19px, 20px];
//etc
}
// Duplicate this since we will be doing more drastic changes
var secondaryDoc = workingDoc.duplicate();
// Select the layer we're working with
selectLayerByID(listOfLayers.i);
// Do the cropping
if(bounds.length > 2) secondaryDoc.crop(bounds); //Each bounds array has 4 elements, check if that's the case to make sure we haven't input any weird values, then crop
else alert('No bounds set up for layer '+name+' in group '+groupName); //in this case it should be cancelled but I'm not sure how to stop the script from executing
// Condense the group 'name', which is the one we're working with, into a single layer for easier management
condenseGroup();
// Remove all the layers that aren't the one we're working with
deleteAllLayersAndGroupsExceptSelected();
// Save as PNG
var pngFile = new File(path+name);
pngSaveOptions = new PNGSaveOptions();
pngSaveOptions.embedColorProfile = true;
pngSaveOptions.formatOptions = FormatOptions.STANDARDBASELINE;
pngSaveOptions.matte = MatteType.NONE; pngSaveOptions.quality = 1;
activeDocument.saveAs(pngFile, pngSaveOptions, false, Extension.LOWERCASE);
// Close this duplicate without saving the PSD
secondaryDoc.close(SaveOptions.DONOTSAVECHANGES);
}
workingDoc.close(SaveOptions.DONOTSAVECHANGES);
}
所以我想摆脱它的是,在具有特定组结构的同时,使它 select 成为层次结构中的一个组,然后将每个子组的内容保存为 PNG将文档裁剪成一组尺寸,但我很难找到正确的方法和功能来完成它。
[编辑] 请求的图像在此处 post 编辑:
这是Layer structure。每个 "Figure_X_bodypart_VariationY" 中都有一组子组。我想通过将文档裁剪到为每个子组编码到脚本中的特定范围来处理这些子组中的每一个。
I have the PSD structured like this, the open folder has a mask, (which is the current selection to show which pixels belong to that layer). I want the script to select a rectangle specified for that one layer, like this.
在那之后,我希望脚本复制文档(这样它就不会弄乱原来的文档),然后crop using the bounds I've given in the script for that group. After that, the script should remove all the other groups so only this one remains,并将其另存为 PNG,然后关闭复制的文档,然后继续下一个子对象。
完成所有子对象后,继续每个 "Figure_X_bodypart_VariationY" 类型组
输入:
输出:
var exportPath = "/C/test-export",
bounds = {
child1: [
44,
92,
338,
363
],
child2: [
263,
62,
536,
315
],
child3: [
160,
269,
458,
497
]
};
cropAndExport("figureA");
function cropAndExport(groupName)
{
var doc = activeDocument;
var masterClone = cloneDoc(); // master clone of the document
masterClone.activeLayer = masterClone.layers.getByName(groupName); // selecting a group by name
var groupChildren = masterClone.activeLayer.layers; // getting children of the group
for (var i = 0; i < groupChildren.length; i++)
{
masterClone.activeLayer = groupChildren[i];
var clone = cloneDoc();
mergeDown(); // merging the group
toggleVisibility(); //hiding all the other groupChildren
rectSelection(bounds[groupChildren[i].name]); //you can use ifs to load bounds you want here, like if (groupChildren[i].name == 'child1') rectSelection(boundChild1);
cropToSelection()
savePng24(groupName, groupChildren[i].name, exportPath)
clone.close(SaveOptions.DONOTSAVECHANGES);
};
masterClone.close(SaveOptions.DONOTSAVECHANGES);
/////////////////////////////////////////////////////////////////////////////////////
// functions
/////////////////////////////////////////////////////////////////////////////////////
function savePng24(nameX, nameY, exportFolder)
{
var pngOpts = new ExportOptionsSaveForWeb;
pngOpts.format = SaveDocumentType.PNG
pngOpts.PNG8 = false;
pngOpts.transparency = true;
activeDocument.exportDocument(new File(exportFolder + "/" + nameX + "_" + nameY + ".png"), ExportType.SAVEFORWEB, pngOpts);
}; // end of savePng24()
function cloneDoc()
{
var desc2 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putEnumerated(cTID('Dcmn'), cTID('Ordn'), cTID('Frst'));
desc2.putReference(cTID('null'), ref1);
desc2.putString(cTID('Nm '), 'clone');
executeAction(cTID('Dplc'), desc2, DialogModes.NO);
return activeDocument;
}; // end of cloneDoc()
function mergeDown()
{
var desc11 = new ActionDescriptor();
executeAction(cTID('Mrg2'), desc11, DialogModes.NO);
}; // end of mergeDown()
function toggleVisibility()
{
var desc102 = new ActionDescriptor();
var list5 = new ActionList();
var ref18 = new ActionReference();
ref18.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
list5.putReference(ref18);
desc102.putList(cTID('null'), list5);
desc102.putBoolean(cTID('TglO'), true);
executeAction(cTID('Shw '), desc102, DialogModes.NO);
}; // end of toggleVisibility()
function rectSelection(data)
{
var desc25 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putProperty(cTID('Chnl'), cTID('fsel'));
desc25.putReference(cTID('null'), ref1);
var desc26 = new ActionDescriptor();
desc26.putUnitDouble(cTID('Left'), cTID('#Pxl'), data[0]);
desc26.putUnitDouble(cTID('Top '), cTID('#Pxl'), data[1]);
desc26.putUnitDouble(cTID('Rght'), cTID('#Pxl'), data[2]);
desc26.putUnitDouble(cTID('Btom'), cTID('#Pxl'), data[3]);
desc25.putObject(cTID('T '), cTID('Rctn'), desc26);
executeAction(cTID('setd'), desc25, DialogModes.NO);
}; // end of rectSelection()
function cropToSelection()
{
var desc33 = new ActionDescriptor();
desc33.putBoolean(cTID('Dlt '), true);
executeAction(cTID('Crop'), desc33, DialogModes.NO);
}; // end of cropToSelection()
function cTID(s)
{
return app.charIDToTypeID(s);
};
function sTID(s)
{
return app.stringIDToTypeID(s);
};
}
第一次post来这里!如果此 post 缺少信息,或者有碍观瞻,我事先表示歉意!
所以,我有一堆层,结构有点像这样的例子:
+ graphics (group, unique)
+ - + Figure_A (group, unique)
+ - + - + Figure_A_arm (group, unique)
+ - + - + - + Figure_A_arm_Variation1 (group, unique)
+ - + - + - + - + frame1_arm (group, not unique)
+ - + - + - + - + - + FigureGraphic (linked layer, not unique, has a mask)
+ - + - + - + - + frame2_arm (group, not unique)
+ - + - + - + - + - + FigureGraphic (linked layer, not unique, has a mask)
+ - + - + - + - + frame2_arm (group, not unique)
+ - + - + - + - + - + FigureGraphic (linked layer, not unique, has a mask)
(unique/notunique表示图层名称是否唯一)
我正在尝试获取组层次结构中最新的像素,文档在自动导出之前被裁剪。主要问题是,有很多功能我无法弄清楚,即使在不停地戳了两个星期之后。我在脚本中挖掘了很多片段,但它变得一团糟,无法正常工作。 我在我想做的事情中包含了一个伪代码。理想情况下,我会编写其中编写的函数,但在谷歌搜索两周后,我无法弄清楚其中的很多内容。 Photoshop 脚本中的很多功能看起来很晦涩,我根本想不通...
我一直在通过从这些地方获取代码片段来编写函数:
导出为 PNG:Photoshop CS6 Export Nested Layers to PNG?
Select 所有子图层:http://www.joonas.me/posts/2018/01/30/select-child-layers-photoshop-script/
获取 selected 图层 ID:https://forums.adobe.com/thread/2256708
Select 图层按 ID:https://forums.adobe.com/thread/2140075
我一直在尝试,但我发现很难实现它们来做我需要的事情,有时我会收到错误或变量变成 'undefined',从而触发错误。
// Here's some 'pseudocode' with how I'm trying to make it work
cropAndSave("Figure_A_arm_Variation1");
cropAndSave("Figure_A_arm_Variation2");
cropAndSave("Figure_A_arm_Variation3");
cropAndSave("Figure_A_leg_Variation1");
cropAndSave("Figure_A_leg_Variation2");
cropAndSave("Figure_A_leg_Variation3");
cropAndSave("Figure_B_arm_Variation1");
cropAndSave("Figure_B_arm_Variation2");
cropAndSave("Figure_B_arm_Variation3");
//etc
function cropAndSave(nameOfGroup)
{
//nameOfGroup is the group layer we are looking for
//Duplicate the document so we don't mess with the original
var workingDoc = app.activeDocument.duplicate();
// Path we want to export to
var path="C:/test/"+nameOfGroup+"/";
// Look up for this group layer in the document
setActiveLayerSet(nameOfGroup);
// Make a list (array?) with the ids of each layer set/group inside nameOfGroup
// This shouldn't include anything inside each group, only the direct groups inside nameOfGroup
var listOfLayers = getListOfChildrenObjects();
// Loop the process for each sub-object
for( var i = 0; i < listOfLayers.length ; i++ )
{
var name = getLayerNameById(listOfLayers.i); //I don't know if this is the correct way to ask for the i element of a list
var bounds = []; //We'll be using this for the cropping
if(groupName=="Figure_A_arm_Variation1") //Checking which set we're doing
{
if(name=="frame1_arm") bounds = [1px, 2px, 3px, 4px]; //just a test value
else if(name=="frame2_arm") bounds = [5px, 6px, 7px, 8px]; //just a test value
else if(name=="frame3_arm") bounds = [9px, 10px, 11px, 12px]; //just a test value
else if(name=="frame1_leg") bounds = [13px, 14px, 15px, 16px]; //just a test value
// and so on
}
else if(groupName=="Figure_B_arm_Variation2") //one of the many possible groups
{
if(name=="frame1_arm") bounds = [17px, 18px, 19px, 20px];
//etc
}
// Duplicate this since we will be doing more drastic changes
var secondaryDoc = workingDoc.duplicate();
// Select the layer we're working with
selectLayerByID(listOfLayers.i);
// Do the cropping
if(bounds.length > 2) secondaryDoc.crop(bounds); //Each bounds array has 4 elements, check if that's the case to make sure we haven't input any weird values, then crop
else alert('No bounds set up for layer '+name+' in group '+groupName); //in this case it should be cancelled but I'm not sure how to stop the script from executing
// Condense the group 'name', which is the one we're working with, into a single layer for easier management
condenseGroup();
// Remove all the layers that aren't the one we're working with
deleteAllLayersAndGroupsExceptSelected();
// Save as PNG
var pngFile = new File(path+name);
pngSaveOptions = new PNGSaveOptions();
pngSaveOptions.embedColorProfile = true;
pngSaveOptions.formatOptions = FormatOptions.STANDARDBASELINE;
pngSaveOptions.matte = MatteType.NONE; pngSaveOptions.quality = 1;
activeDocument.saveAs(pngFile, pngSaveOptions, false, Extension.LOWERCASE);
// Close this duplicate without saving the PSD
secondaryDoc.close(SaveOptions.DONOTSAVECHANGES);
}
workingDoc.close(SaveOptions.DONOTSAVECHANGES);
}
所以我想摆脱它的是,在具有特定组结构的同时,使它 select 成为层次结构中的一个组,然后将每个子组的内容保存为 PNG将文档裁剪成一组尺寸,但我很难找到正确的方法和功能来完成它。
[编辑] 请求的图像在此处 post 编辑:
这是Layer structure。每个 "Figure_X_bodypart_VariationY" 中都有一组子组。我想通过将文档裁剪到为每个子组编码到脚本中的特定范围来处理这些子组中的每一个。
I have the PSD structured like this, the open folder has a mask, (which is the current selection to show which pixels belong to that layer). I want the script to select a rectangle specified for that one layer, like this.
在那之后,我希望脚本复制文档(这样它就不会弄乱原来的文档),然后crop using the bounds I've given in the script for that group. After that, the script should remove all the other groups so only this one remains,并将其另存为 PNG,然后关闭复制的文档,然后继续下一个子对象。
完成所有子对象后,继续每个 "Figure_X_bodypart_VariationY" 类型组
输入:
输出:
var exportPath = "/C/test-export",
bounds = {
child1: [
44,
92,
338,
363
],
child2: [
263,
62,
536,
315
],
child3: [
160,
269,
458,
497
]
};
cropAndExport("figureA");
function cropAndExport(groupName)
{
var doc = activeDocument;
var masterClone = cloneDoc(); // master clone of the document
masterClone.activeLayer = masterClone.layers.getByName(groupName); // selecting a group by name
var groupChildren = masterClone.activeLayer.layers; // getting children of the group
for (var i = 0; i < groupChildren.length; i++)
{
masterClone.activeLayer = groupChildren[i];
var clone = cloneDoc();
mergeDown(); // merging the group
toggleVisibility(); //hiding all the other groupChildren
rectSelection(bounds[groupChildren[i].name]); //you can use ifs to load bounds you want here, like if (groupChildren[i].name == 'child1') rectSelection(boundChild1);
cropToSelection()
savePng24(groupName, groupChildren[i].name, exportPath)
clone.close(SaveOptions.DONOTSAVECHANGES);
};
masterClone.close(SaveOptions.DONOTSAVECHANGES);
/////////////////////////////////////////////////////////////////////////////////////
// functions
/////////////////////////////////////////////////////////////////////////////////////
function savePng24(nameX, nameY, exportFolder)
{
var pngOpts = new ExportOptionsSaveForWeb;
pngOpts.format = SaveDocumentType.PNG
pngOpts.PNG8 = false;
pngOpts.transparency = true;
activeDocument.exportDocument(new File(exportFolder + "/" + nameX + "_" + nameY + ".png"), ExportType.SAVEFORWEB, pngOpts);
}; // end of savePng24()
function cloneDoc()
{
var desc2 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putEnumerated(cTID('Dcmn'), cTID('Ordn'), cTID('Frst'));
desc2.putReference(cTID('null'), ref1);
desc2.putString(cTID('Nm '), 'clone');
executeAction(cTID('Dplc'), desc2, DialogModes.NO);
return activeDocument;
}; // end of cloneDoc()
function mergeDown()
{
var desc11 = new ActionDescriptor();
executeAction(cTID('Mrg2'), desc11, DialogModes.NO);
}; // end of mergeDown()
function toggleVisibility()
{
var desc102 = new ActionDescriptor();
var list5 = new ActionList();
var ref18 = new ActionReference();
ref18.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
list5.putReference(ref18);
desc102.putList(cTID('null'), list5);
desc102.putBoolean(cTID('TglO'), true);
executeAction(cTID('Shw '), desc102, DialogModes.NO);
}; // end of toggleVisibility()
function rectSelection(data)
{
var desc25 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putProperty(cTID('Chnl'), cTID('fsel'));
desc25.putReference(cTID('null'), ref1);
var desc26 = new ActionDescriptor();
desc26.putUnitDouble(cTID('Left'), cTID('#Pxl'), data[0]);
desc26.putUnitDouble(cTID('Top '), cTID('#Pxl'), data[1]);
desc26.putUnitDouble(cTID('Rght'), cTID('#Pxl'), data[2]);
desc26.putUnitDouble(cTID('Btom'), cTID('#Pxl'), data[3]);
desc25.putObject(cTID('T '), cTID('Rctn'), desc26);
executeAction(cTID('setd'), desc25, DialogModes.NO);
}; // end of rectSelection()
function cropToSelection()
{
var desc33 = new ActionDescriptor();
desc33.putBoolean(cTID('Dlt '), true);
executeAction(cTID('Crop'), desc33, DialogModes.NO);
}; // end of cropToSelection()
function cTID(s)
{
return app.charIDToTypeID(s);
};
function sTID(s)
{
return app.stringIDToTypeID(s);
};
}