first time posting here! I apologize beforehand in case this post is missing information, or if it's an eyesore!
So, I have a bunch of layers, structured kinda like this as an example:
+ 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/not unique means if the name of the layer is unique or not)
I'm trying to get the pixels of the latest in the hierarchy of the groups, with the document cropped before an automated export. The main problem is, there are a lot of functions I can't figure out, even after poking at it for two weeks non stop. I've dug a lot of snippets in the script but it's turning into a mess that doesn't work. I am including a pseudo-code with what I'm trying to do. Ideally I'd write the functions written in there, but after googling for two weeks, I can't get a lot of them clear. A lot of functions in Photoshop scripting seem quite obscure and I can't figure them out at all...
I've been writing functions by taking code snippets from these places:
Export to PNG: Photoshop CS6 Export Nested Layers to PNG?
Select all child layers: http://www.joonas.me/posts/2018/01/30/select-child-layers-photoshop-script/
Get selected layer IDs: https://forums.adobe.com/thread/2256708
Select layer by ID: https://forums.adobe.com/thread/2140075
I've been trying but I am finding it difficult to implement them to do what I need, and sometimes I get errors or variables become 'undefined', triggering an error.
// 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);
}
So what I'm trying to get out of it is, while having a specific group structure, make it select a group within the hierarchy, and save the contents of each sub-group as PNG after cropping the document to a set of dimensions, but I'm having difficulties finding the correct way and functions to do it.
[Edit] Requested images are posted here:
This is the Layer structure. Each "Figure_X_bodypart_VariationY" has a set of sub-groups in it. I want to process each of these subgroups by cropping the document to specific bounds that are coded into the script for each one of them.
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.
After that, I want the script to duplicate the document (so it doesn't mess with the original), then 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, and save it as PNG, then close the duplicated document, and proceed to the next sub-object.
After all sub-objects are done, continue with each "Figure_X_bodypart_VariationY" type groups
Input:
Output:
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);
};
}