• Global community
    • Language:
      • Deutsch
      • English
      • EspaƱol
      • FranƧais
      • PortuguĆŖs
  • ę—„ęœ¬čŖžć‚³ćƒŸćƒ„ćƒ‹ćƒ†ć‚£
    Dedicated community for Japanese speakers
  • ķ•œźµ­ ģ»¤ė®¤ė‹ˆķ‹°
    Dedicated community for Korean speakers
Exit
0

Get selected layers

Community Beginner ,
Mar 10, 2011 Mar 10, 2011

Copy link to clipboard

Copied

Hi there.

I've been trying to work with multiple selected layers, but I don't know how to do it. If I select multiple layers, app.activeDocument.activeLayer only returns  the topmost one.

By the way, I'm looking for a way of doing it without using all that low level ActionReference stuff. It really clutters up the code and it's very hard to understand.

Thanks.

TOPICS
Actions and scripting

Views

5.6K

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
Adobe
Valorous Hero ,
Mar 10, 2011 Mar 10, 2011

Copy link to clipboard

Copied

Some things are just not possible with just using the DOM, this is one these.

What you need to do is group the selected layers into a layerset, then you can get the actual layers into an array, then undo the layerset creation.

IE:-

var GroupedLayers = [];
GroupedLayers = GetSelectedLayers();
for(var z in GroupedLayers) {
	alert(GroupedLayers[z].name);
}

function GetSelectedLayers() {
	var A = [];
	var desc11 = new ActionDescriptor();
		var ref9 = new ActionReference();
		ref9.putClass( stringIDToTypeID('layerSection') );
	desc11.putReference( charIDToTypeID('null'), ref9 );
		var ref10 = new ActionReference();
		ref10.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
	desc11.putReference( charIDToTypeID('From'), ref10 );
	executeAction( charIDToTypeID('Mk  '), desc11, DialogModes.NO );
	var gL = activeDocument.activeLayer.layers;
	for(var i = 0; i < gL.length; i++) { 
		A.push(gL[i]); 
	} 
	executeAction( charIDToTypeID('undo'), undefined, DialogModes.NO );
	return A;
};

Votes

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
Explorer ,
Apr 22, 2022 Apr 22, 2022

Copy link to clipboard

Copied

Is there a simple way to use low-level ActionReference stuff to get a list of only the top-level selected layer sets? I've only found examples of these that generate a list of EVERY nested layer -- not the top-level layer sets.

Votes

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
LEGEND ,
Apr 23, 2022 Apr 23, 2022

Copy link to clipboard

Copied

 

sTT = stringIDToTypeID; (ref = new ActionReference())
.putProperty(sTT('property'), hBL = sTT('hasBackgroundLayer'))
ref.putEnumerated(sTT('document'), sTT('ordinal'), sTT('targetEnum'))
bL = executeActionGet(ref).getBoolean(hBL);

(ref = new ActionReference())
.putProperty(sTT('property'), tLs = sTT('targetLayers'))
ref.putEnumerated(sTT('document'), sTT('ordinal'), sTT('targetEnum'))
cnt = (slctd = executeActionGet(ref).getList(tLs)).count; arr = []

for(i = 0; i < cnt;) (ref = new ActionReference())
.putIndex(charIDToTypeID('Lyr '), indx = slctd
.getReference(i++).getIndex() + !bL), typeIDToStringID
((dsc = executeActionGet(ref)).getEnumerationValue
(sTT('layerSection'))).indexOf('Content') < 0
&& dsc.getInteger(sTT('parentLayerID')) < 0
&& arr.push(indx); alert(arr)

 

Votes

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
Explorer ,
Apr 23, 2022 Apr 23, 2022

Copy link to clipboard

Copied

This is really cool! However it currently relays the item index. Can it be modified to output the layer name instead?

Votes

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
LEGEND ,
Apr 24, 2022 Apr 24, 2022

Copy link to clipboard

Copied

LATEST

Change last line to:

&& arr.push(dsc.getString(sTT('name')))
alert(arr)

Votes

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
Guru ,
Mar 10, 2011 Mar 10, 2011

Copy link to clipboard

Copied

I think Xbytor has some code for working with multiple selected layers in his xtools that only uses DOM methods. He wrote it before the ''targetLayers" key was added to the document descriptor.

But the 'low level' action manager code is faster and, once you understand it, easier to use for something like this.

Votes

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
Valorous Hero ,
Mar 10, 2011 Mar 10, 2011

Copy link to clipboard

Copied

I missed targetLayers Mike, I will have a look, many thanks.

Votes

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
Guru ,
Mar 10, 2011 Mar 10, 2011

Copy link to clipboard

Copied

After seeing Paul's post I could be wrong about xtools having a way that only uses DOM methods. Xbytor may have had to use some action mangaer code as well.

Paul, here is an example of working with multiple selected layers using action manager. It will remove 'copy' from the selected layers.

if( app.documents.length > 0 ){
app.activeDocument.suspendHistory('Rename selected layers','removeCopyFromSelectedLayersNames()');
}
function removeCopyFromLayerName(){
     if( getSelectedLayersIdx().length > 1 ){
          var selectedLayers = getSelectedLayersIdx();
          makeActiveByIndex( selectedLayers[0], false );
     }
   var startLoop = Number( !hasBackground() );
   var endLoop = getNumberOfLayer() + 1;
   for( var l = startLoop;l < endLoop; l++){
        while( !isValidActiveLayer( l ) ) {
            l++;
        }
          var oldName =  getLayerNameByIndex( l );
          var newName = oldName.replace(/\scopy\s?\d*$/i,'');
          putLayerNameByIndex( l, newName )
     }
     if( selectedLayers != undefined ) makeActiveByIndex( selectedLayers, false );
}
function removeCopyFromSelectedLayersNames(){
     var selectedLayers = getSelectedLayersIdx();
     for( var l = 0;l < selectedLayers.length; l++){
          var oldName =  getLayerNameByIndex( selectedLayers[ l ] );
          var newName = oldName.replace(/\scopy.*$/i,'');
          makeActiveByIndex( selectedLayers[ l ], false );
          putLayerNameByIndex( selectedLayers[ l ], newName )
     }
     makeActiveByIndex( selectedLayers, false );
}
function getNumberOfLayer(){
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
var desc = executeActionGet(ref);
var numberOfLayer = desc.getInteger(charIDToTypeID('NmbL'));
return numberOfLayer;
}
function getLayerNameByIndex( idx ) {
    var ref = new ActionReference();
    ref.putProperty( charIDToTypeID('Prpr') , charIDToTypeID( 'Nm  ' ));
    ref.putIndex( charIDToTypeID( 'Lyr ' ), idx );
    return executeActionGet(ref).getString(charIDToTypeID( 'Nm  ' ));;
}
function putLayerNameByIndex( idx, name ) {
     if( idx == 0 ) return;
    var desc = new ActionDescriptor();
        var ref = new ActionReference();
        ref.putIndex( charIDToTypeID( 'Lyr ' ), idx );
    desc.putReference( charIDToTypeID('null'), ref );
        var nameDesc = new ActionDescriptor();
        nameDesc.putString( charIDToTypeID('Nm  '), name );
    desc.putObject( charIDToTypeID('T   '), charIDToTypeID('Lyr '), nameDesc );
    executeAction( charIDToTypeID('setd'), desc, DialogModes.NO );
}
function getActiveLayerIndex() {
     var ref = new ActionReference();
     ref.putProperty( 1349677170 , 1232366921 );
     ref.putEnumerated( 1283027488, 1332896878, 1416783732 );
     var res = executeActionGet(ref).getInteger( 1232366921 )
                                                       - Number( hasBackground() );
     return res;  
}
function isValidActiveLayer( idx ) {
     var propName = stringIDToTypeID( 'layerSection' );
     var ref = new ActionReference();
     ref.putProperty( 1349677170 , propName);
     ref.putIndex( 1283027488, idx );
     var desc =  executeActionGet( ref );
     var type = desc.getEnumerationValue( propName );
     var res = typeIDToStringID( type );
     return res == 'layerSectionEnd' ? false:true;
}
function hasBackground(){
    var res = undefined;
    try{
        var ref = new ActionReference();
        ref.putProperty( 1349677170 , 1315774496);
        ref.putIndex( 1283027488, 0 );
        executeActionGet(ref).getString(1315774496 );;
        res = true;
    }catch(e){ res = false}
    return res;
}
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++){
               selectedLayers.push(  desc.getReference( i ).getIndex());
          }
     }else{
          var ref = new ActionReference();
          ref.putProperty( charIDToTypeID('Prpr') , charIDToTypeID( 'ItmI' ));
          ref.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
          selectedLayers.push( executeActionGet(ref).getInteger(charIDToTypeID( 'ItmI' )));
     }
     return selectedLayers;
}
function makeActiveByIndex( idx, visible ){
     if( idx.constructor != Array ) idx = [ idx ];
     for( var i = 0; i < idx.length; i++ ){
          var desc = new ActionDescriptor();
          var ref = new ActionReference();
          ref.putIndex(charIDToTypeID( 'Lyr ' ), idx[i])
          desc.putReference( charIDToTypeID( 'null' ), ref );
          if( i > 0 ) {
               var idselectionModifier = stringIDToTypeID( 'selectionModifier' );
               var idselectionModifierType = stringIDToTypeID( 'selectionModifierType' );
               var idaddToSelection = stringIDToTypeID( 'addToSelection' );
               desc.putEnumerated( idselectionModifier, idselectionModifierType, idaddToSelection );
          }
          desc.putBoolean( charIDToTypeID( 'MkVs' ), visible );
          executeAction( charIDToTypeID( 'slct' ), desc, DialogModes.NO );
     }    
}

Two things to note. The action manager layer index changes depending on if there is a background layer. And in action manager layersets have two indexes one of which you can't do much with. That is the reason for hasBackground() and isValidActiveLayer() ie you can't make the layerSelectionEnds index active.

Note 2. I replaced some of the charIDToTypeID calls with the returned numbers in some of the functions. It makes harder to read but does speed the script up if there are a lot of layers.

 

Message was edited by: Michael L Hale

Votes

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
Valorous Hero ,
Mar 10, 2011 Mar 10, 2011

Copy link to clipboard

Copied

Many thanks for that Mike, I will file it away for later use.

Votes

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
Participant ,
Sep 26, 2014 Sep 26, 2014

Copy link to clipboard

Copied

This is a pretty old thread, but if anyone's still around...

I'm an Applescripter, and I just need to group the already selected layers. I was achieving this fine with user interface scripting and just having it call [command] + , but sometimes, on some people's computers, it's executing steps out of order due to the UI scripting. I've been tweaking delay commands in the script, but it's getting slow and it still doesn't work 100% reliably...

It looks like this functionality isn't available to Applescript, so I was hoping to find a "Do Javascript" call that accomplishes the same thing. I don't know any javascript, but figured I could just run this and then start deleting bits that look promising until only the "group" functionality is still functional. But I keep messing with it and can't get it to run... even just saving the whole thing as a Javascript and running it from the Script menu, I just get General Error 8800 "this functionality may not be available" messages. Any help would be appreciated. Thanks.

Votes

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 ,
Dec 17, 2018 Dec 17, 2018

Copy link to clipboard

Copied

Hi there, I have been struggling with this problem and after a lot of trying and failing, I found a very simple solution that works great as long as you don't use layersets.

hope this helps somebody.

function SelectedLayers() {
	try{
		var ActLay = app.activeDocument.activeLayer;
		ActLay.allLocked = true; //lock all selected layers
		var LayerStack = app.activeDocument.artLayers.length;

		var selLayers = new Array();
		for(var i = 0; i <= LayerStack - 1; i++) {
			ActLay = app.activeDocument.layers[i]
			if (ActLay.allLocked == true) {selLayers.push(app.activeDocument.layers[i]);} // push all locked layers into an array
		}

		for (i = 0; i <= LayerStack - 1; i++) {
			var LAY = app.activeDocument.layers[i];
			LAY.allLocked = false; // unlock all locked Layers
		}

		return selLayers;
	}
	catch(e){/*alert(e);*/}
}

SelectedLayers()

Votes

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
LEGEND ,
Dec 18, 2018 Dec 18, 2018

Copy link to clipboard

Copied

Nice workaround!

Votes

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 ,
Feb 17, 2019 Feb 17, 2019

Copy link to clipboard

Copied

Hello again, after some thinking I got a solution that works also with layersets... yeah! šŸ™‚

function SelectedLayers() {
	try{
		//Version V2 works with folders aka layersets
		var ActLay = app.activeDocument.activeLayer;
		ActLay.allLocked = true;
		var L = app.activeDocument.layers.length;
		var selLayers = new Array();
		for(var i = 0; i < L; i++) {
			var LayerType = app.activeDocument.layers[i].typename;
			var layerRef = app.activeDocument.layers[i];

			if (LayerType == "LayerSet" ) {
				var refLength = layerRef.layers.length;
				for(var j = 0; j < refLength; j++) {
					var refLay = layerRef.layers[j];
					if (refLay.allLocked == true){selLayers.push(refLay)}
				}
				continue;
			}

			if (layerRef.allLocked == true) {selLayers.push(layerRef)}
		}

		ActLay.allLocked = false;
		return selLayers;
	}
	catch (e) {/*alert(e)*/}
}

SelectedLayers()

Votes

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
LEGEND ,
Feb 17, 2019 Feb 17, 2019

Copy link to clipboard

Copied

Again good job. But try to keep locked layers if they were locked before running script šŸ˜‰

Votes

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 ,
Nov 04, 2021 Nov 04, 2021

Copy link to clipboard

Copied

Hi, bjoernu! 

Can I have question about the this part:

var layerRef = app.activeDocument.layers[i];

			if (LayerType == "LayerSet" ) {
				var refLength = layerRef.layers.length;

So 

refLength = app.activeDocument.layers[i].layers.length;

Why is this running well? Layer object doesn't even have properties named 'layers' or 'length'.

Votes

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
Guide ,
Nov 04, 2021 Nov 04, 2021

Copy link to clipboard

Copied

ā€ƒapp.activeDocument.layers == collection (array-like) of Layer objects

2021-11-04_16-49-10.png

Votes

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