7 Replies Latest reply on Dec 17, 2012 3:58 AM by ekiver

    Recursively accessing groups times

    ekiver

      Hi, I noticed that my export script gets slower by the end of exporting, so I stripped out all my custom actions so only basic code is left

       

      function toSetRec(set)

      {

          debug += "*******************\n"; // Timing

       

          var timing = new Date();

          debug += set.name + "\n" + ((timing.getTime()  - startTiming.getTime()) * 0.001) + "s\n"; 

          var count =  set.layerSets.length;

          for(var i = 0; i < count;i++)

          {

              var layerSet = set.layerSets[i];

              var timing = new Date();

              debug +=  "#" + layerSet.name + "\n" + ((timing.getTime()  - startTiming.getTime()) * 0.001) + "s\n"; 

              toSetRec (layerSet);

          }

      }

       

      And the output of this is interesting

       

      It takes less than a secon at script start to access any group:

       

      *******************

      icons

      9.067s

      *******************

      -icons

      9.349s

      *******************

      rnd

      9.396s

      *******************

      -cursors

      9.559s

      *******************

      rnd

      9.624s

      *******************

      @[ICON]hotel jar

      9.807s

      *******************

      ...

       

      But at the end it takes 4 (difference between prev and next times)seconds to access each group (so the whole execution takes

       

      ...

      *******************

      @[ROTATE]tree 7

      603.097s

      *******************

      @[ROTATE]tree 8

      606.914s

      *******************

      @[ROTATE]tree 9

      610.727s

      *******************

      @[ROTATE]tree 10

      614.534s

      *******************

      @[ROTATE]tree 11

      618.389s

      *******************

       

      How can I address this? That would greatly speedup my script

      Thank you

        • 1. Re: Recursively accessing groups times
          Paul Riggott Level 6

          It would be faster using Action Manager code rather than DOM.

          Here is an example you can run on a PSD from ESTK , it should write the layerset name and number of layers to the console.

           

           

           

          #target Photoshop
          main();
          function main(){
          if(!documents.length) return;
          var LayerSetLayers=[];
          var lSets = getLayerSets();
          for(var z in lSets){
          var lset = getChildIndex(Number(lSets[z]), true );
          LayerSetLayers[Number(lSets[z])] = lset;
          }
          for(var a in lSets){
              $.writeln(getLayerNameByIndex( Number(lSets[a])) + " has " + LayerSetLayers[Number(lSets[a])].length + " layers");
              }
          };
          function getLayerSets(){ 
             var ref = new ActionReference(); 
             ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') ); 
             var count = executeActionGet(ref).getInteger(charIDToTypeID('NmbL')) +1; 
             var Lsets=[];
          try{
              activeDocument.backgroundLayer;
          var i = 0; }catch(e){ var i = 1; };
             for(i;i<count;i++){ 
                 if(i == 0) continue;
                  ref = new ActionReference(); 
                  ref.putIndex( charIDToTypeID( 'Lyr ' ), i );
                  var desc = executeActionGet(ref);
                  var layerName = desc.getString(charIDToTypeID( 'Nm  ' ));
                  if(layerName.match(/^<\/Layer group/) ) continue;
                  var layerType = typeIDToStringID(desc.getEnumerationValue( stringIDToTypeID( 'layerSection' )));
                  var isLayerSet =( layerType == 'layerSectionContent') ? false:true;
                  if(isLayerSet) Lsets.push(i);
             }; 
          return Lsets;
          };
          function getLayerLayerSectionByIndex( index ) {   
             var ref = new ActionReference(); 
             ref.putIndex(charIDToTypeID("Lyr "), index);
             return typeIDToStringID(executeActionGet(ref).getEnumerationValue(stringIDToTypeID("layerSection")));
          }; 
          function getLayerNameByIndex( index ) { 
              var ref = new ActionReference(); 
              ref.putIndex( charIDToTypeID( "Lyr " ), index );
              return executeActionGet(ref).getString(charIDToTypeID( "Nm  " ));
          };
          function skipNestedSets( layerIndex ){
             var isEnd = false;
             layerIndex = app.activeDocument.layers[app.activeDocument.layers.length-1].isBackgroundLayer ? layerIndex-2:layerIndex;
             while(!isEnd){
                layerIndex--;
                if( getLayerLayerSectionByIndex( layerIndex ) == 'layerSectionStart' ) layerIndex = skipNestedSets( layerIndex );
                isEnd = getLayerNameByIndex(layerIndex) == "</Layer group>" ? true:false;
             }
             return layerIndex-1;
          };
          function getChildIndex(idx, skipNested ){
             var layerSetIndex = idx;
             var isEndOfSet = false;
             var layerIndexArray = [];
             while(!isEndOfSet){
                layerSetIndex--;
                if( getLayerLayerSectionByIndex( layerSetIndex ) == 'layerSectionStart' && skipNested ){
                   layerSetIndex = skipNestedSets( layerSetIndex );
                }
            if(getLayerLayerSectionByIndex( layerSetIndex ) == undefined) break;
                isEndOfSet = getLayerNameByIndex(layerSetIndex) == "</Layer group>" ? true:false;
               if(!isEndOfSet ) layerIndexArray.push( layerSetIndex );
             }
             return layerIndexArray;
          };
          
          
          • 2. Re: Recursively accessing groups times
            ekiver Level 1

            Thanks, I'll give it a try

            • 3. Re: Recursively accessing groups times
              ekiver Level 1

              Your script runs lightning fast. But I need ArtLayers and LayerSets links to do something with layers. How can I get them? I also didn't quite get what getLayerLayerSectionByIndex()

              does. Script is great but it isnt documented, so its hard to get it.

              • 4. Re: Recursively accessing groups times
                Paul Riggott Level 6

                This idea of getting the layer info is the wonderful work of Mike Hale. Mike is checking the indexs for a start and end of a layerset and returning a list of indexs for that layerset.

                 

                I have added a few comments and some more code on how to select the layers, hope it's a start for you.

                 

                 

                #target Photoshop
                app.bringToFront();
                main();
                function main(){
                if(!documents.length) return;
                var LayerSetLayers=[];
                //complete list of layersets (index of)
                var lSets = getLayerSets();
                for(var z in lSets){
                    //the true means skip any nested layersets, only layers for the selected layerset returned
                var lset = getChildIndex(Number(lSets[z]), true );
                //put a list of the layerset layers so that they can be retrieved later by the layerset index
                LayerSetLayers[Number(lSets[z])] = lset;
                }
                //loop through all the layersets 
                for(var a in lSets){
                    $.writeln(getLayerNameByIndex( Number(lSets[a])) + " has " + LayerSetLayers[Number(lSets[a])].length + " layers");
                    }
                //now you can access all the layers
                //example loop through all the layers in the first layerset
                var LSetToWorkOn = LayerSetLayers[Number(lSets[0])];
                for( var z in LSetToWorkOn){
                    //get the layernames
                    $.writeln(getLayerNameByIndex( Number(LSetToWorkOn[z])));
                    }
                //if you want to work on each layer
                for( var z in LSetToWorkOn){
                    //select each layer in turn
                    selectLayerByIndex( Number(LSetToWorkOn[z]));
                    //do whatever to this layer
                    }
                };
                
                function getLayerSets(){ 
                   var ref = new ActionReference(); 
                   ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') ); 
                   var count = executeActionGet(ref).getInteger(charIDToTypeID('NmbL')) +1; 
                   var Lsets=[];
                try{
                    activeDocument.backgroundLayer;
                var i = 0; }catch(e){ var i = 1; };
                   for(i;i<count;i++){ 
                       if(i == 0) continue;
                        ref = new ActionReference(); 
                        ref.putIndex( charIDToTypeID( 'Lyr ' ), i );
                        var desc = executeActionGet(ref);
                        var layerName = desc.getString(charIDToTypeID( 'Nm  ' ));
                        if(layerName.match(/^<\/Layer group/) ) continue;
                        var layerType = typeIDToStringID(desc.getEnumerationValue( stringIDToTypeID( 'layerSection' )));
                        var isLayerSet =( layerType == 'layerSectionContent') ? false:true;
                        if(isLayerSet) Lsets.push(i);
                   }; 
                return Lsets;
                };
                // returns one of: 
                // 'layerSectionStart'     Start of a layer set 
                // 'layerSectionEnd'       End of a layer set 
                // 'layerSectionConent'  A content layer 
                function getLayerLayerSectionByIndex( index ) {   
                   var ref = new ActionReference(); 
                   ref.putIndex(charIDToTypeID("Lyr "), index);
                   return typeIDToStringID(executeActionGet(ref).getEnumerationValue(stringIDToTypeID("layerSection")));
                }; 
                function getLayerNameByIndex( index ) { 
                    var ref = new ActionReference(); 
                    ref.putIndex( charIDToTypeID( "Lyr " ), index );
                    return executeActionGet(ref).getString(charIDToTypeID( "Nm  " ));
                };
                function skipNestedSets( layerIndex ){
                   var isEnd = false;
                   layerIndex = app.activeDocument.layers[app.activeDocument.layers.length-1].isBackgroundLayer ? layerIndex-2:layerIndex;
                   while(!isEnd){
                      layerIndex--;
                      if( getLayerLayerSectionByIndex( layerIndex ) == 'layerSectionStart' ) layerIndex = skipNestedSets( layerIndex );
                      isEnd = getLayerNameByIndex(layerIndex) == "</Layer group>" ? true:false;
                   }
                   return layerIndex-1;
                };
                function getChildIndex(idx, skipNested ){
                   var layerSetIndex = idx;
                   var isEndOfSet = false;
                   var layerIndexArray = [];
                   while(!isEndOfSet){
                      layerSetIndex--;
                      if( getLayerLayerSectionByIndex( layerSetIndex ) == 'layerSectionStart' && skipNested ){
                         layerSetIndex = skipNestedSets( layerSetIndex );
                      }
                  if(getLayerLayerSectionByIndex( layerSetIndex ) == undefined) break;
                      isEndOfSet = getLayerNameByIndex(layerSetIndex) == "</Layer group>" ? true:false;
                     if(!isEndOfSet ) layerIndexArray.push( layerSetIndex );
                   }
                   return layerIndexArray;
                };
                function selectLayerByIndex(index,add){ 
                 add = (add == undefined)  ? add = false : add;
                 var ref = new ActionReference();
                    ref.putIndex(charIDToTypeID("Lyr "), index);
                    var desc = new ActionDescriptor();
                    desc.putReference(charIDToTypeID("null"), ref );
                       if(add) desc.putEnumerated( stringIDToTypeID( "selectionModifier" ), stringIDToTypeID( "selectionModifierType" ), stringIDToTypeID( "addToSelection" ) ); 
                      desc.putBoolean( charIDToTypeID( "MkVs" ), false ); 
                   try{
                    executeAction(charIDToTypeID("slct"), desc, DialogModes.NO );
                }catch(e){}
                };
                
                 
                
                • 5. Re: Recursively accessing groups times
                  ekiver Level 1

                  Thanks a lot for taking your time adding comments and all, I'll post if I ran into some other troubles

                  • 6. Re: Recursively accessing groups times
                    Paul Riggott Level 6

                    I hope you have had time to study the code. I have added some extra code that will get layers not in layersets and it shows how to get the layer bounds of all layers in all layersets.

                     

                     

                    #target Photoshop
                    app.bringToFront();
                    main();
                    function main(){
                    if(!documents.length) return;
                    var startTime = new Date().getTime();
                    $.writeln("Number of layers = " + noOfLayers());
                    var LayerSetLayers=[];
                    //complete list of layersets (index of)
                    var lSets = getLayerSets();
                    for(var z in lSets){
                        //the true means skip any nested layersets, only layers for the selected layerset returned
                    var lset = getChildIndex(Number(lSets[z]), true );
                    //put a list of the layerset layers so that they can be retrieved later by the layerset index
                    LayerSetLayers[Number(lSets[z])] = lset;
                    }
                    var allLayers=new Array;
                    for(var s in lSets){
                        var layerSetTemp = LayerSetLayers[Number(lSets[s])];
                        for(var f in layerSetTemp){
                            allLayers.push(Number(layerSetTemp[f]));
                            }
                        }
                    ////////////////// Get all layers not in layersets
                    var TopLayers = getIDXs();
                    allLayers.sort(numSortAccending);
                    for(var z in allLayers){
                        for(var s =0;s< TopLayers.length;s++){
                            if(allLayers[z] == TopLayers[s]){
                                TopLayers.splice (s, 1);
                                break;
                                }
                            }
                        }
                    /////////////////////
                    $.writeln('Layers not in layersets and their bounds');
                    $.writeln('Number of top layers = ' + TopLayers.length);
                    for(var t in TopLayers){
                        $.writeln('[' +getLayerNameByIndex( Number(TopLayers[t])) + '] Bounds = ' + getBounds( Number(TopLayers[t])));
                        }
                    $.writeln('--------');
                    //loop through all the layersets 
                    for(var a in lSets){
                        $.writeln(getLayerNameByIndex( Number(lSets[a])) + ' has ' + LayerSetLayers[Number(lSets[a])].length + ' layers');
                        }
                    //now you can access all the layers
                    //example loop through all the layers in each layerset
                    for(var y =0;y<lSets.length;y++){
                    var LSetToWorkOn = LayerSetLayers[Number(lSets[y])];
                    $.writeln("LayerSet = " + getLayerNameByIndex( Number(lSets[y])));
                    for( var z in LSetToWorkOn){
                        //get the layernames and bounds
                        $.writeln(getLayerNameByIndex( Number(LSetToWorkOn[z])) + ' Bounds = ' + getBounds( Number(LSetToWorkOn[z])));
                        }
                    }
                    //if you want to work on each layer
                    for( var z in LSetToWorkOn){
                        //select each layer in turn
                        selectLayerByIndex( Number(LSetToWorkOn[z]));
                        //do whatever to this layer
                        }
                    var endTime = new Date().getTime();
                    var timeTaken = ((endTime - startTime)/1000).toFixed(2);
                    $.writeln("Time taken = " +timeTaken + " seconds");
                    };
                    function noOfLayers(){
                       var ref = new ActionReference(); 
                       ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') ); 
                       return executeActionGet(ref).getInteger(charIDToTypeID('NmbL'));
                    }
                    function getLayerSets(){ 
                       var ref = new ActionReference(); 
                       ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') ); 
                       var count = executeActionGet(ref).getInteger(charIDToTypeID('NmbL')) +1; 
                       var Lsets=[];
                    try{
                        activeDocument.backgroundLayer;
                    var i = 0; }catch(e){ var i = 1; };
                       for(i;i<count;i++){ 
                           if(i == 0) continue;
                            ref = new ActionReference(); 
                            ref.putIndex( charIDToTypeID( 'Lyr ' ), i );
                            var desc = executeActionGet(ref);
                            var layerName = desc.getString(charIDToTypeID( 'Nm  ' ));
                            if(layerName.match(/^<\/Layer group/) ) continue;
                            var layerType = typeIDToStringID(desc.getEnumerationValue( stringIDToTypeID( 'layerSection' )));
                            var isLayerSet =( layerType == 'layerSectionContent') ? false:true;
                            if(isLayerSet) Lsets.push(i);
                       }; 
                    return Lsets;
                    };
                    // returns one of: 
                    // 'layerSectionStart'     Start of a layer set 
                    // 'layerSectionEnd'       End of a layer set 
                    // 'layerSectionConent'  A content layer 
                    function getLayerLayerSectionByIndex( index ) {   
                       var ref = new ActionReference(); 
                       ref.putIndex(charIDToTypeID('Lyr '), index);
                       return typeIDToStringID(executeActionGet(ref).getEnumerationValue(stringIDToTypeID('layerSection')));
                    }; 
                    function getLayerNameByIndex( index ) { 
                        var ref = new ActionReference(); 
                        ref.putIndex( charIDToTypeID( 'Lyr ' ), index );
                        return executeActionGet(ref).getString(charIDToTypeID( 'Nm  ' ));
                    };
                    function skipNestedSets( layerIndex ){
                       var isEnd = false;
                       layerIndex = app.activeDocument.layers[app.activeDocument.layers.length-1].isBackgroundLayer ? layerIndex-2:layerIndex;
                       while(!isEnd){
                          layerIndex--;
                          if( getLayerLayerSectionByIndex( layerIndex ) == 'layerSectionStart' ) layerIndex = skipNestedSets( layerIndex );
                          isEnd = getLayerNameByIndex(layerIndex) == '</Layer group>' ? true:false;
                       }
                       return layerIndex-1;
                    };
                    function getChildIndex(idx, skipNested ){
                       var layerSetIndex = idx;
                       var isEndOfSet = false;
                       var layerIndexArray = [];
                       while(!isEndOfSet){
                          layerSetIndex--;
                          if( getLayerLayerSectionByIndex( layerSetIndex ) == 'layerSectionStart' && skipNested ){
                             layerSetIndex = skipNestedSets( layerSetIndex );
                          }
                      if(getLayerLayerSectionByIndex( layerSetIndex ) == undefined) break;
                          isEndOfSet = getLayerNameByIndex(layerSetIndex) == '</Layer group>' ? true:false;
                         if(!isEndOfSet ) layerIndexArray.push( layerSetIndex );
                       }
                       return layerIndexArray;
                    };
                    function getBounds(idx){
                    var ref = new ActionReference(); 
                    ref.putIndex(charIDToTypeID('Lyr '), idx);
                    var desc = executeActionGet(ref).getObjectValue(stringIDToTypeID( 'bounds' ));
                    var bounds = [];
                    bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('left')));
                    bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('top')));
                    bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('right')));
                    bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('bottom'))); 
                    return bounds;
                    }
                    function selectLayerByIndex(index,add){ 
                     add = (add == undefined)  ? add = false : add;
                     var ref = new ActionReference();
                        ref.putIndex(charIDToTypeID('Lyr '), index);
                        var desc = new ActionDescriptor();
                        desc.putReference(charIDToTypeID('null'), ref );
                           if(add) desc.putEnumerated( stringIDToTypeID( 'selectionModifier' ), stringIDToTypeID( 'selectionModifierType' ), stringIDToTypeID( 'addToSelection' ) ); 
                          desc.putBoolean( charIDToTypeID( 'MkVs' ), false ); 
                       try{
                        executeAction(charIDToTypeID('slct'), desc, DialogModes.NO );
                    }catch(e){}
                    };
                    function getIDXs(){ 
                       var ref = new ActionReference(); 
                       ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') ); 
                       var count = executeActionGet(ref).getInteger(charIDToTypeID('NmbL')) +1; 
                       var IDX=[];
                    try{
                        activeDocument.backgroundLayer;
                    var i = 0; }catch(e){ var i = 1; };
                       for(i;i<count;i++){ 
                           if(i == 0) continue;
                            ref = new ActionReference(); 
                            ref.putIndex( charIDToTypeID( 'Lyr ' ), i );
                            var desc = executeActionGet(ref);
                            var layerName = desc.getString(charIDToTypeID( 'Nm  ' ));
                            var Id = desc.getInteger(stringIDToTypeID( 'layerID' ));
                            if(layerName.match(/^<\/Layer group/) ) continue;
                            var layerType = typeIDToStringID(desc.getEnumerationValue( stringIDToTypeID( 'layerSection' )));
                            var isLayerSet =( layerType == 'layerSectionContent') ? false:true;
                            if(!isLayerSet) IDX.push(i);
                       }; 
                    return IDX;
                    };
                    function numSortAccending(a, b){ return (a-b); } 
                    
                     
                    
                    • 7. Re: Recursively accessing groups times
                      ekiver Level 1

                      Hi Paul, thank you very much! We were just working with your previous post, and it helps a lot. I guess with latest version it will be even more sraightforward.