9 Replies Latest reply on Feb 25, 2018 2:51 PM by OMOTI

    Photoshop Scripting: Group Document Layers/Group Into One Group

    mollys36035936

      Hi,

       

      I have a script that I'm trying to build upon and streamline. This current script works in this way:

       

      • Creates a new document called "Clipped Group."
      • Iterates through all open documents.
      • If there is one group in each document, and that group is called "Group 1," duplicate that group into the "Clipped Group" document.

       

      This script works great, but it involves some setup by the user in order for it to work. The setup that I would like to eliminate is having the user go through each open document beforehand and group all of the layers they need into a group called "Group 1." I would like to just have all layers and groups added to the new "Group 1" group as they are in the document by building on my current script. This is the part of the script that works fine, but requires some setup:

       

      var docRef = app.activeDocument;    
          
      function makePackageDoc(filename) {    
          if (app.documents.length > 0) {    
              var docHeight = 4000;    
              var docWidth = 6000;    
              app.documents.add(docWidth, docHeight, 300, "Clipped Group", NewDocumentMode.RGB, DocumentFill.TRANSPARENT, 1.0, BitsPerChannelType.EIGHT, "test");    
          };    
      };    
          
      function moveComponentGroup() {    
          for (var i = 0; i < app.documents.length; i++) {  //Script iterates through all open documents.    
              docRef = app.documents[i];
              if (docRef.name == "Clipped Group") {
                  continue;    
              };    
              var x = docRef.layerSets.length;    
              if ((x > 0) && (docRef.layerSets[0].name == "Group 1" )) {    
                  app.activeDocument = docRef;  
                  docRef.layerSets[0].duplicate(app.documents["Clipped Group"].layers[0], ElementPlacement.PLACEBEFORE);         
              };    
          };    
      };    
          
      makePackageDoc("Clipped Group");    
      moveComponentGroup(); 
      

       

      Here is what I've come up with in trying to get write the script so that it instead automatically groups all of the current document's layers and groups (as they are) into a new group:

       

      var docRef = app.activeDocument;    
          
      function makePackageDoc(filename) {    
          if (app.documents.length > 0) {    
              var docHeight = 4000;    
              var docWidth = 6000;    
              app.documents.add(docWidth, docHeight, 300, "Clipped Group", NewDocumentMode.RGB, DocumentFill.TRANSPARENT, 1.0, BitsPerChannelType.EIGHT, "test");    
          };    
      };
      
      
      function groupLayers () {
          for (var i = 0; i < app.documents.length; i++) {
              
              var newGroup = docRef.layerSets.add();
              newGroup.name = "New Group";
              
              var numOfLayers = docRef.layers.length;
              
              for (var k = 0; k < numOfLayers; k++) {
                  var currentLayer = docRef.layers[k];
                  if (currentLayer.name != "New Group" ) {
                      docRef.layerSets["New Group"].move(currentLayer, ElementPlacement.INSIDE);
                  };
              };
          };
      };
          
      function moveComponentGroup() {    
          for (var i = 0; i < app.documents.length; i++) {  //Script iterates through all open documents.    
              docRef = app.documents[i];
              if (docRef.name == "Clipped Group") {
                  continue;    
              };    
              var x = docRef.layerSets.length;    
              if ((x > 0) && (docRef.layerSets[0].name == "New Group" )) {    
                  app.activeDocument = docRef;  
                  docRef.layerSets[0].duplicate(app.documents["Clipped Group"].layers[0], ElementPlacement.PLACEBEFORE);         
              };    
          };    
      };
      
      
      groupLayers();
      
      
      makePackageDoc("Clipped Group"); 
      
      
      moveComponentGroup(); 
      

       

      It's definitely getting messed up in the groupLayers function, but I'm quite stuck and can't figure out how to fix this. I think part of the issue is that I'm not sure how to reference the "New Group" group in order to move the layers/groups into it. Am I on the right track? Any advice would be appreciated. Txhank you.

        • 1. Re: Photoshop Scripting: Group Document Layers/Group Into One Group
          OMOTI Level 3

          Hi,

           

          Please be conscious of the scope of variables. "docRef" variable is strange.

           

          And, The target will be reverse.

          // Bad: Put a layerset in the layer.

          docRef.layerSets["New Group"].move(currentLayer, ElementPlacement.INSIDE);
          

          // OK: Put a layer in the layerset.

          currentLayer.move(docRef.layerSets["New Group"], ElementPlacement.INSIDE);
          

           

          Does this following script work fine?

           

          (function () {
              
              var DOCUMENT_NAME = 'Clipped Group',
                  GROUP_NAME = 'New Group';
              
              function makePackageDoc(filename) {
                  var docHeight = 4000,
                      docWidth = 6000;
                  if (app.documents.length > 0) {
                      app.documents.add(docWidth, docHeight, 300, filename, NewDocumentMode.RGB, DocumentFill.TRANSPARENT, 1.0, BitsPerChannelType.EIGHT, "test");
                  }
              }
          
              function groupLayers() {
                  var i,
                      max;
                  
                  function collect(docRef) {
                      var newGroup,
                          i,
                          min;
                      app.activeDocument = docRef;
                      newGroup = docRef.layerSets.add();
                      newGroup.name = GROUP_NAME;
                      for (i = docRef.layers.length - 1, min = 0; min < i; i -= 1) {
                          docRef.layers[i].move(newGroup, ElementPlacement.INSIDE);
                      }
                  }
                  
                  for (i = 0, max = app.documents.length; i < max; i += 1) {
                      collect(app.documents[i]);
                  }
              }
          
              function moveComponentGroup() {
                  var docRef,
                      i,
                      max;
                  for (i = 0, max = app.documents.length; i < max; i += 1) {
                      docRef = app.documents[i];
                      if (docRef.name === DOCUMENT_NAME) {
                          continue;
                      }
                      if ((docRef.layerSets.length > 0) && (docRef.layerSets[0].name === GROUP_NAME)) {
                          app.activeDocument = docRef;
                          docRef.layerSets[0].duplicate(app.documents[DOCUMENT_NAME].layers[0], ElementPlacement.PLACEBEFORE);
                      }
                  }
              }
          
          
              function main() {
                  groupLayers();
                  makePackageDoc(DOCUMENT_NAME);
                  moveComponentGroup();
              }
              
              main();
              
          }());
          
          • 2. Re: Photoshop Scripting: Group Document Layers/Group Into One Group
            mollys36035936 Level 1

            Thanks for the input OMOTI. I tried to use the script you gave, but it runs into an error on Line 30 whenever I try to run it: "Undefined is not an object." I think I can still glean some useful things from your input though, especially since I was reversing the target you mentioned above.

            • 3. Re: Photoshop Scripting: Group Document Layers/Group Into One Group
              OMOTI Level 3

              Hi,

              Please open one or more documents and execute the script.

              The layers of these opened documents are duplicated to the new document 'Clipped Group'.

              • 4. Re: Photoshop Scripting: Group Document Layers/Group Into One Group
                mollys36035936 Level 1

                Hi OMOTI,

                 

                Whoops, I wasn't executing the script correctly. I no longer get the error "Undefined is not an object" when I execute, but I did get an error based on line 26 that indicated that if there is a "Background" layer, this layer can't be moved like normal layers. This shouldn't be an issue for me since I can ignore "Background" layers in my particular workflow for this, so I added an exception to the for loop to skip trying to move that layer:

                 

                for (i = docRef.layers.length - 1, min = 0; min < i; i -= 1) {
                    if (docRef.layers.name == "Background") {
                        continue;
                    } else {
                        docRef.layers[i].move(newGroup, ElementPlacement.INSIDE);
                

                 

                I was able to run the script again when I added that exception, but then I got an error at the very end of the script:

                 

                }());  // error: ) does not have a value
                


                In any case, the script errors out and nothing happens in Ps, though I'm testing on a group of images with many layers and layersets. Does the exception I added make sense? And should there be a value added to the final parentheses?

                 

                Thanks for all the help.

                • 5. Re: Photoshop Scripting: Group Document Layers/Group Into One Group
                  OMOTI Level 3

                  Hi mollys,

                   

                  Close, but not right.

                   

                  docRef.layers is 'Layers'.

                  docRef.layers[i] is 'Layer'.

                   

                  Does it work as follows?

                  for (i = docRef.layers.length - 1, min = 0; min < i; i -= 1) {
                      if (docRef.layers[i].name === "Background") {
                          continue;
                      } else {
                          docRef.layers[i].move(newGroup, ElementPlacement.INSIDE);
                  
                  1 person found this helpful
                  • 6. Re: Photoshop Scripting: Group Document Layers/Group Into One Group
                    mollys36035936 Level 1

                    OMOTI, of course, that makes way more sense, thank you. I updated the script again to include that change. I tried running it again with some complex PSDs open in Ps, but I still get an error on the final line. I included the script again with changes below, and the error coming up at line 63. Any thoughts on this? Thanks again.

                     

                     

                    (function () {  
                          
                        var DOCUMENT_NAME = 'Clipped Group',  
                            GROUP_NAME = 'New Group';  
                          
                        function makePackageDoc(filename) {  
                            var docHeight = 4000,  
                                docWidth = 6000;  
                            if (app.documents.length > 0) {  
                                app.documents.add(docWidth, docHeight, 300, filename, NewDocumentMode.RGB, DocumentFill.TRANSPARENT, 1.0, BitsPerChannelType.EIGHT, "test");  
                            }  
                        }  
                      
                        function groupLayers() {  
                            var i,  
                                max;  
                              
                            function collect(docRef) {  
                                var newGroup,  
                                    i,  
                                    min;  
                                app.activeDocument = docRef;  
                                newGroup = docRef.layerSets.add();  
                                newGroup.name = GROUP_NAME;  
                                for (i = docRef.layers.length - 1, min = 0; min < i; i -= 1) {  
                                    if (docRef.layers[i].name === "Background") {  
                                       continue;  
                                    } else {  
                                       docRef.layers[i].move(newGroup, ElementPlacement.INSIDE);  
                                }  
                            }
                              
                            for (i = 0, max = app.documents.length; i < max; i += 1) {  
                                collect(app.documents[i]);  
                            }  
                        }  
                      
                        function moveComponentGroup() {  
                            var docRef,  
                                i,  
                                max;  
                            for (i = 0, max = app.documents.length; i < max; i += 1) {  
                                docRef = app.documents[i];  
                                if (docRef.name === DOCUMENT_NAME) {  
                                    continue;  
                                }  
                                if ((docRef.layerSets.length > 0) && (docRef.layerSets[0].name === GROUP_NAME)) {  
                                    app.activeDocument = docRef;  
                                    docRef.layerSets[0].duplicate(app.documents[DOCUMENT_NAME].layers[0], ElementPlacement.PLACEBEFORE);  
                                }  
                            }  
                        }  
                      
                      
                        function main() {  
                            groupLayers();  
                            makePackageDoc(DOCUMENT_NAME);  
                            moveComponentGroup();  
                        }  
                          
                        main();  
                          
                    }());  // error: ') does not have a value'
                    
                    • 7. Re: Photoshop Scripting: Group Document Layers/Group Into One Group
                      OMOTI Level 3

                      The closing brackets for 'else block' is not enough at line 30.

                       

                      function collect(docRef) {

                          var newGroup,

                              i,

                              min;

                          app.activeDocument = docRef;

                          newGroup = docRef.layerSets.add();

                          newGroup.name = GROUP_NAME;

                          for (i = docRef.layers.length - 1, min = 0; min < i; i -= 1) {

                              if (docRef.layers[i].name === "Background") {

                                  continue;

                              } else {

                                  docRef.layers[i].move(newGroup, ElementPlacement.INSIDE);

                              } // <- here

                          }

                      }

                      1 person found this helpful
                      • 8. Re: Photoshop Scripting: Group Document Layers/Group Into One Group
                        mollys36035936 Level 1

                        Hi OMOTI,

                         

                        I added that missing bracket. I'm unfortunately getting this error now, shown in comment below:

                         

                        function collect(docRef) {    
                                    var newGroup,    
                                        i,    
                                        min;    
                                    app.activeDocument = docRef;    
                                    newGroup = docRef.layerSets.add();    
                                    newGroup.name = GROUP_NAME;    
                                    for (i = docRef.layers.length - 1, min = 0; min < i; i -= 1) {    
                                        if (docRef.layers[i].name === "Background") {    
                                           continue;    
                                        } else {    
                                           docRef.layers[i].move(newGroup, ElementPlacement.INSIDE);//ERROR: illegal argument
                                        }
                        

                         

                        So I think I know what might be the problem here. When I try and run this script on a complex PSD that has a mixture of groups and plain layers (layers that aren't in any groups whatsoever), only the layers that aren't in any groups move to the "New Group" group that's being created from this script. I think the reason for that is the script only knows how to move plain layers that aren't in a group, but not actual layer sets, which is why it says that line is an illegal argument. Just having the "layers" property doesn't seem to be enough for the script to be able to move everything into the new group. What I thought could fix this is if the script could tell when it's dealing with a layer (ArtLayer) or a group (LayerSet). I tried tweaking the function collect(docRef) to try and solve this:

                         

                        function collect(docRef) {  
                                    var newGroup,  
                                        i,  
                                        min;  
                                    app.activeDocument = docRef;  
                                    newGroup = docRef.layerSets.add();  
                                    newGroup.name = GROUP_NAME;
                                    for (i = docRef.artLayers.length - 1, min = 0; min < i; i -= 1) {
                                        docRef.activeLayer = docRef.artLayers[i];
                                        if (docRef.artLayers[i].name === "Background") {  
                                           continue;  
                                        } else if (docRef.activeLayer.typename === 'ArtLayer') { 
                                            docRef.artLayers[i].move(newGroup, ElementPlacement.INSIDE);
                                        } else if (docRef.activeLayer.typename === 'LayerSet') {
                                            docRef.artLayers[i].move(newGroup, ElementPlacement.INSIDE);
                                        }
                                    }  
                                }
                        

                         

                        I actually got the script to go all the way to making the "Clipped Group" document, and adding all of the New Groups to that document (yay), and some of the groups even had layers in them. However, I still ran into the same issue where it's only grabbing plain layers not within any group and moving them to the "New Group" group. It's not picking up actual groups/layersets and also moving those to the "New Group" group.

                         

                        I think we're getting pretty close, if you had any more thoughts or insight that would be awesome. Otherwise, I'll keep picking away at this.