6 Replies Latest reply on Sep 26, 2014 3:30 PM by TomT-shirts

    Get selected layers


      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.



        • 1. Re: Get selected layers
          Paul Riggott Level 6

          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.



          var GroupedLayers = [];
          GroupedLayers = GetSelectedLayers();
          for(var z in GroupedLayers){
          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++){ 
          executeAction( charIDToTypeID('undo'), undefined, DialogModes.NO );
          return A;
          • 2. Re: Get selected layers
            Michael L Hale Level 5

            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.

            • 3. Re: Get selected layers
              Paul Riggott Level 6

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

              • 4. Re: Get selected layers
                Michael L Hale Level 5

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

                • 5. Re: Get selected layers
                  Paul Riggott Level 6

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

                  • 6. Re: Get selected layers
                    TomT-shirts Level 1

                    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] + [g], 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.