Photoshop get names of selected layers...

Unfortunately from my own research I believe this just may not be possible, even in CS6, but just wanted to see if anyone had solutions, be it Javascript or other methods as well.

I am just looking for a way to get a list of all selected layers in the current document.

It is easy enough to get the name of a single selected layer:


tell application "Adobe Photoshop CS6"
	tell current document to set layerName to name of current layer
end tell

But unfortunately, “current layer” does not provide a list of multiple layers when multiple layers are selected, and only gives you the name of the top most layer.

Anyone have any ideas or methods to get the name of multiple selected layers? Thanks!

current layer is the active layer, and there can only ever be one, by definition. I presume you are after the list of layers selected in the Layers panel, and there’s no way of getting that. OTOH, you can get the layers holding the selection.

Yep you got it.

What do you mean I can get the layers holding the selection? Do you mean layers that fall within a marquee selection? Because that works even better for what I am doing.

I mean any layers containing a selected item:

tell application id "com.adobe.InDesign" 
	try
		set theLayers to item layer of selection
	on error
		-- not a suitable selection, do what you will
	end try
end tell

Layers in Photoshop are quite different to layers in Indesign or Illustrator, I don’t think that is something that will work in Photoshop.

Sorry – I mis-read it as InDesign.

Ah no worries. Thanks for the help.

And DAMN YOU ADOBE! DAMN YOU!!! (SHAKING FIST VIOLENTLY!)

Probably possible since CS2 but you need to use Action Manager code and the scriptlistener plug-in. Very little has changed to the PS regular DOM. but new stuff can be exposed to this Action Manager.

scriptlistener stuff isn’t dynamic at all though so I don’t think it will really help me with what I am after. I have used scriptlistener stuff before but maybe I am misunderstanding? Thanks for the help.

You use the scriptlistener plug-in to record. ( get the internal 4 character codes ) there is no list for these.
Once you have done that you create your own javascript functions to make your script logic.
What you want to be looking at are the classes.
ActionDescriptor and ActionReference these allow you to get and set all kind of object properties that photoshop didn’t bother to add to the regular DOM.

I do loads of stuff in PS such as layer styles and layer masking that you just can’t access.
There are a couple of things that still can’t be done but those you can count with your fingers.

Take a look at. http://www.ps-scripts.com by far the best reference for using action manger syntax.

Yeah my understanding of that stuff is that you are essentially “recording” each action you take and can then use that as reference to do many things, but I don’t quite understand how that would allow me to dynamically pull the name of multiple selected layers as text.

For what I am working on, I can’t really rely on the user having to enable the scriptlistener plugin, or installing any extra tools, I suppose I could enable this as part of the script but I definitely want to avoid that if possible.

They don’t need to. The code behind this is the same a when playing or recording a action in Photoshop. I would think it’s similar to AppleScript’s class identifiers under the hood. As an action it just plays it out. As script you give it logic. I leave the plug-in active but theres no need it can be moved in/out as needed.

This is a sample from around 5 years ago ( CS2 )

The subs just play javascript/action manager code but I can work with multi-layers no problem. You use AppleScript or JavaScript to get the document in the correct state. Then execute action manager when you need to access stuff not in the DOM. continue.

tell application "Adobe Photoshop CS2"
	activate
	set Doc_Ref to the current document
	tell Doc_Ref
		my Select_Layers(Doc_Ref, "Layer 1", "addToSelectionContinuous")
		my Align_Layers(Doc_Ref, "AdBt")
		my Distribute_Layers(Doc_Ref, "AdCH")
	end tell
end tell

on Select_Layers(Doc_Ref, Layer_Ref, Add_Ref)
	-- Layer_Ref = Name string of layer to add to selection
	-- Add_Ref = addToSelection or addToSelectionContinuous
	tell application "Adobe Photoshop CS2"
		tell Doc_Ref
			do javascript "Select_Layers(); function Select_Layers() { function cTID(s) { return app.charIDToTypeID(s); }; function sTID(s) { return app.stringIDToTypeID(s); }; var desc01 = new ActionDescriptor(); var ref01 = new ActionReference(); ref01.putName( cTID('Lyr '), '" & Layer_Ref & "' ); desc01.putReference( cTID('null'), ref01 ); desc01.putEnumerated( sTID('selectionModifier'), sTID('selectionModifierType'), sTID('" & Add_Ref & "') ); desc01.putBoolean( cTID('MkVs'), false ); executeAction( cTID('slct'), desc01, DialogModes.NO );};" show debugger on runtime error
		end tell
	end tell
end Select_Layers

on Align_Layers(Doc_Ref, Align_Ref)
	-- Align_Ref = AdLf, AdRg, AdCH, AdTp, AdBt, AdCV
	tell application "Adobe Photoshop CS2"
		tell Doc_Ref
			do javascript "Align_Layers(); function Align_Layers() {function cTID(s) { return app.charIDToTypeID(s); }; function sTID(s) { return app.stringIDToTypeID(s); }; var desc01 = new ActionDescriptor(); var ref01 = new ActionReference(); ref01.putEnumerated( cTID('Lyr '), cTID('Ordn'), cTID('Trgt') ); desc01.putReference( cTID('null'), ref01 ); desc01.putEnumerated( cTID('Usng'), cTID('ADSt'), cTID('" & Align_Ref & "') ); executeAction( cTID('Algn'), desc01, DialogModes.NO );};" show debugger on runtime error
		end tell
	end tell
end Align_Layers

on Distribute_Layers(Doc_Ref, Distribute_Ref)
	-- Distribute_Ref = AdLf, AdRg, AdCH, AdTp, AdBt, AdCV
	tell application "Adobe Photoshop CS2"
		tell Doc_Ref
			do javascript "Distribute_Layers(); function Distribute_Layers() {function cTID(s) { return app.charIDToTypeID(s); }; function sTID(s) { return app.stringIDToTypeID(s); }; var desc01 = new ActionDescriptor(); var ref01 = new ActionReference(); ref01.putEnumerated( cTID('Lyr '), cTID('Ordn'), cTID('Trgt') ); desc01.putReference( cTID('null'), ref01 ); desc01.putEnumerated( cTID('Usng'), cTID('ADSt'), cTID('" & Distribute_Ref & "') ); executeAction( cTID('Dstr'), desc01, DialogModes.NO );};" show debugger on runtime error
		end tell
	end tell
end Distribute_Layers

The problem is in actually being able to get the names of the currently selected layers, not to interact with the currently selected layers necessarily, I don’t think there is anything scriptlistener is going to spit out that will directly feed the name back.

Why do you need to get the selected layers? What is the bigger picture? There may be a way of working around.

I am actually pulling data out of the history log based on the currently selected layer and I would like to write to a new log file:

LAYERNAME 1

Log data…
Log data…
Log data…
Log data…
Log data…

LAYERNAME 2

Log data…
Log data…
Log data…
Log data…
Log data…

Everything else is ready to go, I just can’t find a good way to get the selected layer names, I can iterate through all the layers in a document, but that doesn’t really help me. I could also get what I need if I could find a way to select multiple layers, and then iterate through those selected layers one at a time, selecting each one individually.

Or… If there is a way to get a list of all layers that include a layer style?

If you want to write a log of styling info. a list of properties for each then you will need action manager code to do that. The only other way would be to parse the binary photoshop file. I have a pdf of the photoshop file spec if that helps it has all the markers you would need to look for.?

I actually have a way to grab a log of the styling info, quite a hack but it works. If you enable history logging in preferences (which can be easily automated with AppleScript, I can also set the name/location of the log file as well), and open close the Layer Style window for a layer, all the Layer Style data gets written to the log. Since I can easily enable/disable logging and use command line tools to grab the data that gets written to the log, I can make that work.

If there is a way to write this data the the history log without opening the Layer Styles window for that layer that would help as well. But if I can just find a way to work with the selected layers I am good to go basically.

May be interested in the file spec though, are there actually reasonable ways to parse the binary file?

This is ExtendScript with action manager syntax. If you save as a *.jsx file you can use it as a do javascript and pass it as file alias or read it in. As is it will alert you the selected layer names. line 13 but you could change that to.

return layerNames.reverse().join( ‘\r’ );

If you set a variable to paragraphs of do javascript command. PM me you email and I can send file spec should you need it.

#target Photoshop
main();
function main(){
if(!documents.length) return;
//list of selected layers index’s
var selectedLayers = getSelectedLayersIdx();
var layerNames=new Array();
//get layer names and put them in an array along with the index
for(var a in selectedLayers){
layerNames.push( getNameByIndex(Number(selectedLayers[a])) );
}
//display the information
alert( layerNames.reverse().join( ‘\r’ ) );
}

//Functions
function getSelectedLayersIdx(){
var selectedLayers = new Array;
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID(‘Dcmn’), charIDToTypeID(‘Ordn’), charIDToTypeID(‘Trgt’) );
var desc = executeActionGet(ref);
if( desc.hasKey( stringIDToTypeID( ‘targetLayers’ ) ) ){
desc = desc.getList( stringIDToTypeID( ‘targetLayers’ ));
var c = desc.count
var selectedLayers = new Array();
for(var i=0;i<c;i++){
try{
activeDocument.backgroundLayer;
selectedLayers.push( desc.getReference( i ).getIndex() );
}catch(e){
selectedLayers.push( desc.getReference( i ).getIndex()+1 );
}
}
}else{
var ref = new ActionReference();
ref.putProperty( charIDToTypeID(‘Prpr’) , charIDToTypeID( ‘ItmI’ ));
ref.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID(‘Ordn’), charIDToTypeID(‘Trgt’) );
try{
activeDocument.backgroundLayer;
selectedLayers.push( executeActionGet(ref).getInteger(charIDToTypeID( ‘ItmI’ ))-1);
}catch(e){
selectedLayers.push( executeActionGet(ref).getInteger(charIDToTypeID( ‘ItmI’ )));
}
}
return selectedLayers;
};
function getNameByIndex(idx){
ref = new ActionReference();
ref.putProperty( charIDToTypeID(“Prpr”) , charIDToTypeID( "Nm " ));
ref.putIndex( charIDToTypeID( "Lyr " ), idx );
return executeActionGet(ref).getString(charIDToTypeID( "Nm " ));
};

Thank you very much! Got it feeding the layer names back into AppleScript as a list exactly how I wanted. My next step may be getting layer indexes for each selected layer as well so I can select each one individually. I will need to be able to select layers that are within groups or nested groups as well.

Or… I may be able to find another way to have Photoshop write the layer style data to the history. Currently I need each individual layer to be selected, open up the Layer Styles window, make no changes, close it, photoshop writes the data to the log, move onto the next layer and repeat. This requires the Layer Styles window to popup for every selected layer and close, which isn’t a huge problem but if it can be avoided it would be much better. I already have a working solution to do this, but as I mentioned it requires each layer to be selected individually so the Layer Styles window can be opened and closed for each layer. Hopefully I can find a way to simplify this a bit, but if not, should I be able to get the index of each selected layer and have a way to reselect them even if they are nested within groups?

The above sample should work regardless of layer structure. Selected layers can be in layer sets, sub sets, top level or any mixture of the above? I tested with several options. Action manager indexes from bottom thats why I reverse the returned array. Glad it helped.