Copy link to clipboard
Copied
Hi there,
I'm having a hard time figuring out how to iterate through all layers/layer groups, getting alerts to give layer names, checking if layer.name.contains my tag, and more...
My goal is to export "Save for Web" JPEGs by finding layers marked with a tag.
The tag would be inside the layer name (example "[e]" ), though it could be something else.
The images can be nested within many folders, and I need the reference of certain folders to hide them.
The layer structure is usually layerGroup2> ..... > layerGroup7> layerGroup14> [e] image, image2, etc..
I'm thinking the process would be:
- iterate through all files and folders
- check if name contains tag
- if true, show layer, change export name+path, export, hide layer
- do this untill all images of layerGroup is exported, then hide layerGroup
My script runs right through to the alert "Export Complete". Even though my psd has many layers and layer groups with "[e]" tagged in their name. I'm not sure what I did wrong.
Here's my test psd layer setup:
Note: I come from C# background, this is my first javascript/ps script attempt.
Also I cut off the export function since its very long.
//====== Heres my code: ===================
#target photoshop
app.bringToFront();
// Summary: Exports tagged layers as JPEGs.
//======= Ref Var =============
var doc = app.activeDocument;
var layerName = ""; //container to pass final layer name
var exportPath = ""; //container to pass final export Path
var exportName = ""; //container to pass final export Name
//====== Var Options ==============
var tag = "[e]"; // layers tag, helps determin which layers to edit
var themeName = "newTHEME"; // name to be change at export
var exportPathLocation = "~/Desktop/"; //default export location
//====== Export Name + Path ===========
// *Note* Ideally names wouldn't be in order and are given based on which parented layer groups its in.
var exportNames = // array of names in order to be used when exporting
[
"unique-THEME-export-name-HEX-paper-size",
"etc...",
"etc..."
];
// *Note* Ideally this script would create the folders at the desktop.
var exportPaths // array of export paths in order to be used when exporting
[
"\\Folder1\\Folder2\\Folder2_1",
"etc...",
"etc..."
];
// ==================== Main Script ====================
ExportAll(); // start script
function ExportAll() // the main body of the script
{
//1) iterate through all layer groups
for (var groupI = doc.layerSets.length - 1; groupI < 0; groupI--) // *Note* This setup assumes all layers will be in layer groups, I'd prefer it didnt.
{
alert('layerSets' + layerSets[i].name); //debug doesnt show name
if(layerSets[i].name.contains(tag)) //check if layer group has tag
{
Show(layerSets[i].name); //show layer group if so
//2) iterate through all layers within groups
for (var layerI = doc.artLayers.length - 1; layerI < 0; layerI--)
{
if(artLayers[i].name.contains(tag)) //check if layer group has tag
{
alert('artLayers' + artLayers[i].name); //debug doesnt show name
//3) show selected layer
Show(artLayers[i].name); //show layer
//4) update the export name and path
exportName = exportNames[groupI]; //export name changes based on layer group
exportName.replace("HEX", "HEX" + [layerI + 1]); // HEX# changes based on layer iteration #
exportName.replace("THEME", themeName); // rename the export Theme name
exportPath = exportPathLocation + exportPaths[groupI]; //destination folder + sub folder paths
//5) export
Export(exportPath, exportName);
alert('exported:' + exportName + "\n to: " + exportPath); //debug
//6) hide selected layer, increment untill all layers are exported then go to the next layer group
Hide(artLayers[i].name); //hide layer
}
}
Hide(layerSets[i].name); //hide layer group
}
}
//7) Completed Message
alert('Export Complete');
}
// ==================== Commands ====================
// *Note* These commands were taken from the ScriptListenerJs.
function Hide(layerName)
{
var idHd = charIDToTypeID( "Hd " );
var desc183 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var list34 = new ActionList();
var ref19 = new ActionReference();
var idLyr = charIDToTypeID( "Lyr " );
ref19.putName( idLyr, layerName ); //layer name
list34.putReference( ref19 );
desc183.putList( idnull, list34 );
executeAction( idHd, desc183, DialogModes.NO );
}
function Show(layerName)
{
var idShw = charIDToTypeID( "Shw " );
var desc184 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var list35 = new ActionList();
var ref20 = new ActionReference();
var idLyr = charIDToTypeID( "Lyr " );
ref20.putName( idLyr, layerName ); // layer name
list35.putReference( ref20 );
desc184.putList( idnull, list35 );
executeAction( idShw, desc184, DialogModes.NO );
}
function Export(exportPath, exportName)
{
//----------------------------------------
//*Note* This first part showed before the export command so I included it.
var idinvokeCommand = stringIDToTypeID( "invokeCommand" );
var desc185 = new ActionDescriptor();
var idcommandID = stringIDToTypeID( "commandID" );
desc185.putInteger( idcommandID, 1695 );
var idkcanDispatchWhileModal = stringIDToTypeID( "kcanDispatchWhileModal" );
desc185.putBoolean( idkcanDispatchWhileModal, true );
executeAction( idinvokeCommand, desc185, DialogModes.NO );
// ---------------------------------------
var idExpr = charIDToTypeID( "Expr" );
var desc186 = new ActionDescriptor();
var idUsng = charIDToTypeID( "Usng" );
var desc187 = new ActionDescriptor();
var idOp = charIDToTypeID( "Op " );
var idSWOp = charIDToTypeID( "SWOp" );
var idOpSa = charIDToTypeID( "OpSa" );
desc187.putEnumerated( idOp, idSWOp, idOpSa );
var idDIDr = charIDToTypeID( "DIDr" );
desc187.putBoolean( idDIDr, true );
var idIn = charIDToTypeID( "In " );
desc187.putPath( idIn, new File( exportPathFolder + exportPath ) ); //export path
var idovFN = charIDToTypeID( "ovFN" );
desc187.putString( idovFN, exportName ); //export name
//lots more export settings etc...
}
I've been trying at this for a few days now, any help is very much appreciated!
Here are a few things. to go through each layer you need a recursive function or an action manager routine, which is faster, but here's the recursive function:
var doc = activeDocument;
var curLayer
goThroughLayers (doc);
function goThroughLayers(parentLayer){
for(var i=0;i<parentLayer.layers.length;i++){
curLayer = parentLayer.layers[i];
doc.activeLayer = curLayer;
if(curLayer.typename =='LayerSet'){goThroughLayers (curLayer)}
else{
if(curLayer.n
...
Copy link to clipboard
Copied
Here are a few things. to go through each layer you need a recursive function or an action manager routine, which is faster, but here's the recursive function:
var doc = activeDocument;
var curLayer
goThroughLayers (doc);
function goThroughLayers(parentLayer){
for(var i=0;i<parentLayer.layers.length;i++){
curLayer = parentLayer.layers[i];
doc.activeLayer = curLayer;
if(curLayer.typename =='LayerSet'){goThroughLayers (curLayer)}
else{
if(curLayer.name=='my layer name'|| curLayer.kind = LayerKind.NORMAL){
if(curLayer.name.match (/[e]/ig)){alert('match')}
}//end if
}//end else
}//end loop
}//end function
To create folders on the desktop:
var exportPath(new Folder('~/desktop/folder1);
if(!folder1.exists){folder1.create()};
You can create a loop to go through an array of folder names to create them.
You don't need this code - it's garbage that scriptListener creates:
var idinvokeCommand = stringIDToTypeID( "invokeCommand" );
var desc185 = new ActionDescriptor();
var idcommandID = stringIDToTypeID( "commandID" );
desc185.putInteger( idcommandID, 1695 );
var idkcanDispatchWhileModal = stringIDToTypeID( "kcanDispatchWhileModal" );
desc185.putBoolean( idkcanDispatchWhileModal, true );
executeAction( idinvokeCommand, desc185, DialogModes.NO );
Copy link to clipboard
Copied
I tried the script and it punched down all the way to the bottom of a 10 deep set of layers and layersets but only affected the layers not the layersets.
how would I modify it to affect the layersets as well? Such as reanmrename to get names, etc.
- DC
Copy link to clipboard
Copied
In my script, you would add any code you want to do on groups in the if function that checks for layer sets. Of course, you want to add that code before the line that reruns the loop function.
Copy link to clipboard
Copied
Example of layer enumeration with Action Manager. Subdirectories are formed using the DOM functions (it can be done through Action Manager, but more code is needed). I did not write the export function - it can be taken from the Event Listener, passing the path to the folder and file name as input parameters.
For an best result, you need to check all layers not only by name, but also by type, leaving adjustment layers (if they are located above the desired layer within the same group))
#target photoshop
// define the start index (depends of a background layer in the document)
var ref = new ActionReference()
ref.putProperty(s2t("property"), s2t("hasBackgroundLayer"))
ref.putEnumerated(s2t("document"), s2t("ordinal"), s2t("targetEnum"))
var from = executeActionGet(ref).getBoolean(s2t("hasBackgroundLayer")) ? 0 : 1
//get the total number of layers (including hidden layerSectionEnd layers)
var ref = new ActionReference()
ref.putProperty(s2t("property"), s2t("numberOfLayers"))
ref.putEnumerated(s2t("document"), s2t("ordinal"), s2t("targetEnum"))
var len = executeActionGet(ref).getInteger(s2t("numberOfLayers"));
var markedLrs = []
//check the name of each layer
for (var i = from; i <= len; i++) {
// do not check group names, but make it visible
ref = new ActionReference();
ref.putProperty(s2t("property"), s2t("layerSection"))
ref.putIndex(s2t("layer"), i)
if (t2s(executeActionGet(ref).getEnumerationValue(s2t("layerSection"))) != "layerSectionContent") {
layerVisibilityByIndex (i, true)
continue;
}
// get and check the name of the layer
ref = new ActionReference();
ref.putProperty(s2t("property"), s2t("name"))
ref.putIndex(s2t("layer"), i)
var lrName = executeActionGet(ref).getString(s2t("name"))
if (lrName.match(/\[e\]/ig)) markedLrs.push({ name: lrName.replace(/\[e\]? /ig, ""), index: i })
// hide the layer, because its visibility may interfere with our export
layerVisibilityByIndex(i, false)
}
// variables to describe the save path and file extension
fld = "~/desktop",
ext = "jpg";
for (var i = 0; i < markedLrs.length; i++) {
// select and make layer visible
selectLayerByIndex(markedLrs[i].index)
layerVisibilityByIndex(markedLrs[i].index, true)
// build the full save path
alert("exort current layer to:\n" + new File(fld + "/" + getGroupPath(markedLrs[i].index) + "/" + markedLrs[i].name + "." + ext).fsName)
// hide current layer
layerVisibilityByIndex(markedLrs[i].index, false)
}
// function that receives subdirectories based on group names
function getGroupPath() {
var lrParent = activeDocument.activeLayer.parent
var pth = []
do {
if (lrParent != activeDocument && lrParent.name.match(/\[e\]/ig)) {
pth.unshift(lrParent.name.replace(/\[e\]? /ig, ""))
lrParent = lrParent.parent
}
else { break; }
} while (true)
return pth.join('/')
}
// select layer by its index
function selectLayerByIndex(idx) {
var desc = new ActionDescriptor()
var ref = new ActionReference()
ref.putIndex(s2t("layer"), idx)
desc.putReference(s2t("null"), ref)
executeAction(s2t("select"), desc, DialogModes.NO)
}
// hide or show layer by its index
function layerVisibilityByIndex(idx, makeVisible) {
makeVisible = makeVisible == true ? "show" : "hide"
var desc = new ActionDescriptor()
var ref = new ActionReference()
ref.putIndex(s2t("layer"), idx)
desc.putReference(s2t("null"), ref)
executeAction(s2t(makeVisible), desc, DialogModes.NO);
}
function s2t(s) { return stringIDToTypeID(s) }
function t2s(t) { return typeIDToStringID(t) }
Copy link to clipboard
Copied
Thanks for your awnser but ill need to give the right answer to Chuck Uebele, since it helped me understand the process better. I tried your code, its nice and works as is but was harder to alter to my needs. Thank you both.