Loop Trough Nested Layers

Photoshop Script Snippets - Note: Full Scripts go in the Photoshop Scripts Forum

Moderators: Tom, Kukurykus

Dido_BG

Loop Trough Nested Layers

Post by Dido_BG »

Hi there people!

Here is a nice way to loop trough nested layers using the DOM.
The script is just counting the layers and layer sets and displaying the elapsed time but easily can be edited for other purposes.
One important thing is that the script is not going straight wich means that loops in the following way:

1) All document's layers
2) All main sets
3) Nested sets, nested sets …

P.S. People with CS2 will be lucky, its performing a lot faster in that version.


Code: Select all

// GLOBAL VARIABLES ====================================================================================== //

var docRef = app.activeDocument;
var docLys = docRef.layers.length;   // All document's layers //
var allLys = 0;                  // All layers (counter) //
var allSts = 0;                  // All sets (counter) //
var actLay;                     // The active layer is going to be placed here //

var setArray = [];   // Detected sets are goingto be placed here //
var cnt = 0;      // Counter for the main layers loop //

// FUNCTIONS ============================================================================================ //

function cntTime (elap){ // Time Calculation //
      
    tmArray = [
   
    "Empty",
       
    [ Math.floor ( (elap/(1000*60*60)) %24) ],   // Hours //
    [ Math.floor ( (elap/(1000*60)) % 60) ],   // Minutes //
    [ Math.floor ( (elap/1000) % 60 ) ]      // Seconds //
   
    ]
   
    for (i=1; i<=3; i++){ // Loop trough the values //       
       
       tmArray = (tmArray < 10 ? "0" : "") + tmArray // If the value is less than 10 // Add 0 //   
   
    }
   
}

// ==================================================================================================== //

function activeLay (lyr){
   
   actLay = lyr
   docRef.activeLayer = actLay // Set the active layer //

}

// ==================================================================================================== //

function setInArray (set){
   
   if (set.typename == 'LayerSet'){   // Check active layer type //
      allSts ++
      setArray.push (set)            // Place the set in the array  //
   }
   else{
      allLys ++
   }

}

// ==================================================================================================== //

function loopInSets (set){ // Loop trough nested layers //

var length = set.layers.length-1   // All layers in the set //

for (i=0; i<=length; i++){

      activeLay (set.layers)   // Set active layer  //
      setInArray (actLay)         // Place subsets in the array //

}
      setArray.splice (0,1)      // Remove the checked set from the array //
}

// GET STARTING TIME ================================================================================== //

   var stDate = new Date ()      // Get starting date //
   var stTime = stDate.getTime ()   // Get starting time //

// START PROCESS ====================================================================================== //

try{
   
   while ( cnt !== docLys+1){
      activeLay (docRef.layers[cnt])      // Set active layer //
      setInArray (actLay)               // Check for set //
      cnt ++
   }
   
}
catch (e){ // Catch error when doument`s layers end // Loop trough sets //
      
   while ( setArray.length !==0 ){      // Loop until the array is not empty  //
      
      loopInSets (setArray[0])      // Always work with the 0 element in the array //
      
   }
}

// ================================================================================================== //

// COUNT THE TIME =================================================================================== //

   var ndDate = new Date ();      // End date //
   var ndTime = ndDate.getTime ();   // End time //

   var elapsed = ndTime - stTime;   // Elapsed time //
   var tmArray = ["Empty", ]      // Time array //

   cntTime (elapsed) // Count the time //

   alert (
          
          "Total Sets " + allSts + "\n\n"
          
          + "Total Layers: " + allLys + "\n\n"
          
          + "Time Elapsed: " + tmArray[2] + " : " + tmArray[3]   // Изминало време //
                    
          + "   " , 'Statistic'
       
        )





Dido_BG

Loop Trough Nested Layers

Post by Dido_BG »

This one loops trough all visible layers except for first hidden layers in the sets. I dont know how is with versions higher than CS3 but CS2 performs much faster. My best result was to loop trough 471 layers/Sets ( all visible ) for 54 seconds in CS2 and 2 and a half minutes in CS3.

Code: Select allvar docRef = app.activeDocument;
var actLay;

function selectNext (){   // Select`s the layer below the active one // Recording from "script listener" //
   
var id3 = charIDToTypeID( "slct" );
    var desc2 = new ActionDescriptor();
    var id4 = charIDToTypeID( "null" );
        var ref1 = new ActionReference();
        var id5 = charIDToTypeID( "Lyr " );
        var id6 = charIDToTypeID( "Ordn" );
        var id7 = charIDToTypeID( "Bckw" );
        ref1.putEnumerated( id5, id6, id7 );
    desc2.putReference( id4, ref1 );
    var id8 = charIDToTypeID( "MkVs" );
    desc2.putBoolean( id8, true );
executeAction( id3, desc2, DialogModes.NO );

}

var tmpLay = docRef.artLayers.add ()

function checkType ( lyr ){                        // Check the type  //

   if ( lyr.typename == "LayerSet"  ) {               // If the layer is "Set" //
      
      if ( lyr.layers.length != 0 ){                  // If the "set" is not empty //

         docRef.activeLayer = lyr.layers[0]         // Make the first layer in the set active //
         checkType ( docRef.activeLayer )         // Call the function again  // In case the new active is "set" too //

      }
      else {                           // If the "set" is empty //

         lyr.remove ()                     // Remove the empty "set" //
         checkType ( docRef.activeLayer )         // Check the previous layer again //

      }

   }

}

function loopLayers (){                        // Loop function //
   
   selectNext ()                           // Select next layer   //
   actLay = docRef.activeLayer                  // Put the new one in the variable //
      
   checkType ( actLay )                        // Check the type //

   if ( actLay != tmpLay ){                     // If all layers are not checked  //
         
      loopLayers ()                        // Call the function again //
         
   }
   else{                                 // If all layers are checked  //
      
      tmpLay.remove ()                     // Remove temp layer //

   }
   
}

loopLayers ()                              // Loop //

alert ( "All layers checked" )



And here is a straight way using the DOM.

Code: Select all

var docRef = app.activeDocument;
var actLay;

var ind = 0;
var lastInd = [];

var tmpLay = docRef.artLayers.add ();

if ( docRef.layers[ docRef.layers.length-1 ].isBackgroundLayer == true ){
         
   tmpLay.move ( docRef.layers[ docRef.layers.length-1 ], ElementPlacement.PLACEBEFORE )
   
}
else{
   
   tmpLay.move ( docRef.layers[ docRef.layers.length-1 ], ElementPlacement.PLACEAFTER )
   
}

function checkType ( lyr ){
   
   if ( lyr.typename == "LayerSet" ){
      
      lastInd.push ( ind )         // Put the current index in the array //
      ind = 0               // Restart the counter //
      
      loopLayers ( lyr )         // Start checking in the set //
   
   }
   
}

function loopLayers ( par ){   // par - parent //
      
   try{
   
      actLay = par.layers[ ind ]
   
   }
   catch (e){      // If the end of the parent is reached //
   
      ind = lastInd[ lastInd.length - 1 ] + 1   // Increase the last index in the array by one  and give it to the counter //
      lastInd.splice ( lastInd.length - 1, 1 )   // Remove the last index from the array //
      
      loopLayers ( par.parent )         // Check one level above //
      
   }
   
   docRef.activeLayer = actLay   
   
   checkType ( actLay )         // Check the current layer //
   
   if ( actLay != tmpLay ) {      // If the temp layer is not reached //
      
      ind++            // Increase the counter //
      loopLayers ( par )      // Check in the same parent //
   
   }
   else{
   }
      
}

   loopLayers ( docRef )      // Check in the active document //
   
   tmpLay.remove ()

alert ( "All Layers Checked" )

Jeremy Knudsen

Loop Trough Nested Layers

Post by Jeremy Knudsen »

I get an "Internal error" on the following line:
Code: Select all   tmpLay.move ( docRef.layers[ docRef.layers.length-1 ], ElementPlacement.PLACEAFTER );
Dido_BG

Loop Trough Nested Layers

Post by Dido_BG »

Hi Jeremy, i`ve edit the code and it`s working now. The problem was that when you have a background layer you can`t paste another layer after it.