• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers

Photoshop script - iterating through all layers and groups to export tagged layers in javascript

New Here ,
Jan 13, 2020 Jan 13, 2020

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:

Screenshot_1.png

 

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!

TOPICS
Actions and scripting

Views

5.7K

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Community Expert , Jan 13, 2020 Jan 13, 2020

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
...

Likes

Translate

Translate
Community Expert ,
Jan 13, 2020 Jan 13, 2020

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 );

 

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Oct 27, 2022 Oct 27, 2022

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

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Oct 27, 2022 Oct 27, 2022

Copy link to clipboard

Copied

LATEST

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.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 15, 2020 Jan 15, 2020

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) }

 

 

 

 

 

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Jan 25, 2020 Jan 25, 2020

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.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines