11 Replies Latest reply on Jan 2, 2017 12:54 AM by JavierAroche

    Getting the children of a selected group

    simene49649793

      I'm still trying to get the hang of Action Manager code, but I keep hitting a wall. I'm trying to figure out how I can get all of the children of the selected group, but I can't find a way to do this.

       

      - How can I retrieve all elements below a group (LayerSet) through AM code?

      - Is it possible to retrieve the parent of a specific layer?

      - Is it possible to collapse/expand groups with AM code?

       

      How do you guys attack these kinds of challenges? I have googled and searched github for these questions, but I haven't found anything of help. I feel like there's just a few of you that knows AM code, how did you plow your way into learning AM coding? I mean, the basic operations that can be recorded by the listener is doable even for me, but approaching challenges like the one's I have now, I don't even know where to start?

        • 1. Re: Getting the children of a selected group
          pixxxel schubser MVP & Adobe Community Professional

          Hi simene49649793,

          there is a script study years ago written by Michael L. Hale (RIP)

           

          This should help you out:

          // written by Michael L.Hale
          
          // selektiert alle Ebenen in der aktiven Gruppe
          // assumes the group you want to select the layer in is the activeLayer
          var groupStartIdx = getActiveLayerIndex();
          app.activeDocument.activeLayer = app.activeDocument.activeLayer.layers[app.activeDocument.activeLayer.layers.length-1];
          var groupEndIdx = getActiveLayerIndex();
          for(l=groupEndIdx;l<groupStartIdx;l++){
              addToLayerSelectionByIndex( l );
          }
             
          function addToLayerSelectionByIndex( idx ) {
              var desc = new ActionDescriptor();
                  var ref = new ActionReference();
                  ref.putIndex( charIDToTypeID('Lyr '), idx );
              desc.putReference( charIDToTypeID('null'), ref );
              desc.putEnumerated( stringIDToTypeID('selectionModifier'), stringIDToTypeID('selectionModifierType'), stringIDToTypeID('addToSelection') );
              desc.putBoolean( charIDToTypeID('MkVs'), false );
              executeAction( charIDToTypeID('slct'), desc, DialogModes.NO );
          };
          function getActiveLayerIndex() {
              var ref = new ActionReference();
              ref.putProperty( charIDToTypeID("Prpr") , charIDToTypeID( "ItmI" ));
              ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
              var res = executeActionGet(ref).getInteger(charIDToTypeID( "ItmI" )) - Number( hasBackground() );
              return res; 
          };
          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;
          };
          

           

          Have fun

           

          1 person found this helpful
          • 2. Re: Getting the children of a selected group
            JavierAroche Level 3

            Hey simene49649793, these 2 functions should get you half way there.

             

            getDocumentInfo() - Retrieves the document information. Super cool function that I found in one of these forums. This is similar to Generator's getDocumentInfo. It has some optional params to retrieve more specific data.

            This AM function will return the document object as a string, because ExtendScript is very limited unfortunately. You will have to parse it using a JSON polyfill. I use this one: https://github.com/JavierAroche/descriptor-info/blob/master/example/helpers/JSON.jsx

            You can then grab the document.layers key which includes all the layers in the document.

            function getDocumentInfo() {
              // Build Action Descriptor
              var ref = new ActionReference();
              var desc = new ActionDescriptor();
              var psJSON = stringIDToTypeID("json");
              ref.putProperty(charIDToTypeID('Prpr'), psJSON);
              ref.putEnumerated(stringIDToTypeID("document"), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));
              desc.putReference(charIDToTypeID('null'), ref);
            // desc.putBoolean(stringIDToTypeID("expandSmartObjects"), true);
            // desc.putBoolean(stringIDToTypeID("selectedLayers"), true);
            // desc.putBoolean(stringIDToTypeID("getTextStyles"), true);
            // desc.putBoolean(stringIDToTypeID("getFullTextStyles"), true);
            // desc.putBoolean(stringIDToTypeID("getDefaultLayerFX"), true);
            // desc.putBoolean(stringIDToTypeID("getPathData"), true);
              return executeAction(charIDToTypeID( "getd" ), desc, DialogModes.NO).getString(psJSON);
            }
            

             

            getSelectedLayerIDs() - Retrieves the selected layer IDs as an array.

            function getSelectedLayerIDs() {
              var selectedLayerIDs = [];
              // Filter selected layers
              var docRef = new ActionReference();
              docRef.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
              var docDesc = executeActionGet(docRef);
            
              // Get target layer ids
              if( docDesc.hasKey(stringIDToTypeID('targetLayersIDs'))) {
              targetLayersIDsDesc = docDesc.getList( stringIDToTypeID('targetLayersIDs'));
            
              for(var ii = 0; ii < targetLayersIDsDesc.count; ii++) {
              selectedLayerIDs.push(Number(targetLayersIDsDesc.getReference( ii ).getIdentifier()));
              }
              }
            
              return selectedLayerIDs;
            }
            

             

            Once you have the document layers as an object and the selected layer IDs, you can simply iterate through all the layers (recursive function) until you find the one you're looking for. If you're only targeting one group layer, it will be a lot easier.

             

            - Is it possible to retrieve the parent of a specific layer?

            This one is tricky, but if you're comfortable with recursive functions, you should be able to get the parent layer of the any layer in a document.

             

            collapseAllGroups() - Collapses all document groups.

            function collapseAllGroups() {
                try {
                    var idcollapseAllGroupsEvent = stringIDToTypeID( "collapseAllGroupsEvent" );
                    var desc13 = new ActionDescriptor();
                    return executeAction( idcollapseAllGroupsEvent, desc13, DialogModes.NO );
                } catch(err) {}
            }
            
            

            How do you guys attack these kinds of challenges? I have googled and searched github for these questions, but I haven't found anything of help. I feel like there's just a few of you that knows AM code, how did you plow your way into learning AM coding? I mean, the basic operations that can be recorded by the listener is doable even for me, but approaching challenges like the one's I have now, I don't even know where to start?

            It takes a lot of practice, patience, googling and spending lots of hours in forums

            DBarranca is authoring a Photoshop Scripting book. That will be great for people trying to learn all of this.

            http://www.davidebarranca.com/2016/10/new-course-photoshop-scripting/

             

            Some resources that have helped me a lot:

             

            I made this little module to better understand Action Descriptors.

            https://github.com/JavierAroche/descriptor-info

             

            Hope it helps!

            3 people found this helpful
            • 3. Re: Getting the children of a selected group
              SuperMerlin Level 5

              The code is here to get layerset layers...

              https://www.ps-scripts.com/viewtopic.php?f=68&t=11268

              2 people found this helpful
              • 4. Re: Getting the children of a selected group
                Jarda Bereza Level 4

                If want select all nested layers in one selected group then you can simply

                1) create group - Ctrl + G

                2) remove group - Ctrl + Shift + G

                3) now you have all nested layers selected (recursively)

                4) get selected layers indexes/ids

                 

                This should have good performance for complex nested layers.

                 

                Parent of specific layer

                1) select your layer by index/id

                2) app.activeDocument.activeLayer.parent.id

                1 person found this helpful
                • 5. Re: Getting the children of a selected group
                  pixxxel schubser MVP & Adobe Community Professional

                  Hi Jarda Bereza,

                  did you try the performance of the code in the last three posts? Do you have problems with the performance of it?

                   

                   

                  Perhaps you can show a working code snippet for making a time comparison? I like to learn.

                   

                  • 6. Re: Getting the children of a selected group
                    Jarda Bereza Level 4

                    pixxxel schubser  napsal(a):

                    Perhaps you can show a working code snippet for making a time comparison? I like to learn.

                     

                    I did some time measurement.

                    Document has 1634 layers, 287 groups and 11136px × 6740px

                    1) 64 layers selected in 5 groups - 1402ms

                    2) 141 layers selected in 32 groups - 291ms

                    (ExtendScript Toolkit his buil-in time measurement features.)

                     

                    Limitations:

                    - you can't group artboards

                    - you can create only 10 nested groups

                     

                    If you select one layer by ID/index it should be +- 20ms per layer

                    DOM recursion is slow. With ActionManager you can read layers, they don't have tree structure but it is linear structure. So it is very fast, but you probably need select layers one by one. You can select layers range, but I am not sure how much reliably it is.

                     

                    Code here: http://pastebin.com/dgUqSb1nhttp://pastebin.com/dgUqSb1n

                    1 person found this helpful
                    • 7. Re: Getting the children of a selected group
                      cbuliarca Level 3

                      I've aproach these problems into my toggle open close groups script, there is also a function that can get the children and one that can get the parent with AM. You will find them in this collection:

                       

                      GitHub - cbuliarca/BCM_exetndShortcutsUI: Collection of Photoshop scripts accesed with an UI, main focused on game textu…

                       

                      just go to the BCM_ToolsUi/ extras/scripts and here the file with all the necessay functions  is mb_utils.jsxinc

                      1 person found this helpful
                      • 8. Re: Getting the children of a selected group
                        pixxxel schubser MVP & Adobe Community Professional

                        Great.

                        The TO simene49649793 ask: "It is possible? How can I do this?"

                         

                        And we start a very usefully discussion about: What is the first class way to do this?

                        I will also take a look next year on the several links. Thx for this.

                         

                         

                        I wish you all the best and a Happy New Year 2017

                        • 9. Re: Getting the children of a selected group
                          simene49649793 Level 1

                          pixxxel schubser: That was a clever way to do it! I've been able to retrieve all children of selected groups using this method, works great I would wish it was possible to retrieve them without making selections, but if I can figure out how to collapse groups afterwards it won't matter Also, using this method I think it should be easy to find the parent layer also by just decreasing the layer index until a hit a LayerSet, I'll try that later. Thank you

                           

                          JavierAroche: That getDocumentInfo was awesome I couldn't get collapseAllGroups to work though, it doesn't seem to do anything Thank you for all of the resources

                           

                          Thank you everyone, this is extremely interesting and helpful! I'm still looking for a way to collapse/expand LayerSets, so if anyone have any ideas on how to do this I'd be really interested to hear how it can be done Happy new year guys, and thanks again

                          • 10. Re: Getting the children of a selected group
                            cbuliarca Level 3

                            You can actually use AM to get the childrens of a layerset, without selecting each layer, that's the beauty of AM. I'm using it to get the chlid layers like this: I'm starting on the parent layerset and set a variable x to 1, then with a loop I go backwards by using the putIndex method for the layer class, with index set to i--, and everytime I get an LayerSectionStart, I'm incrementing the x var, and if I get an LayerSectionEnd I'm decrementing x, when I get x to be equal to 0, I stop the loop, and this way I know that all the layers gathered in an array while the loop run, are the child layers. I usually gather the id's of the layers, the idx and the names...this way I can use another function to select all the layers by Id.

                             

                            As for the closing of a layer group I've solved it by selecting all the child layers, unparent them and group them into another set. And set the properties of the second set similar to the first group...Expanding the layer set it's easy you just have to select one child of that layer set. please take a look of the script I've mention to see how I've done it.

                             

                            Thank you. And Happy New Year to you all.

                            1 person found this helpful
                            • 11. Re: Getting the children of a selected group
                              JavierAroche Level 3

                              I couldn't get collapseAllGroups to work though, it doesn't seem to do anything

                              simene49649793 - That's weird, maybe the "collapseAllGroupsEvent" isn't available in your version of Photoshop? I just tested that same function and it seems to be working on Photoshop CC 2014.2.2 and CC 2015.0.0.