15 Replies Latest reply on Sep 5, 2017 1:40 PM by Tomas Sinkunas

    Get layerSet size but ignore Effect layer.

    Tomas Sinkunas Level 3

      Hey guys. I found myself in a trouble. Here's a screenshot.

      Screen Shot 2017-08-04 at 14.09.16.png

       

      I need to get Group size, however, Levels effect seems to brake it:/

       

      app.activeDocument.activeLayer.boundsNoEffects;

       

      If Groups is selected, it returns 0 px,0 px,500 px,500 px

      If LAYER is selected, it returns 125 px,200 px,375 px,300 px

       

      So my question is - is it possible to ignore Levels Size? Because they brake my calculations, and I need to get a result 125 px,200 px,375 px,300 px if Group is selected. Is this somehow doable?

        • 1. Re: Get layerSet size but ignore Effect layer.
          Chuck Uebele Adobe Community Professional & MVP

          The only way I think you can get around this is a clumsy workaround. Get the code to dupe the layer group, merge the copy of the group, get your layer bounds, then delete the duped group.

          1 person found this helpful
          • 2. Re: Get layerSet size but ignore Effect layer.
            Jarda Bereza Level 4

            Maybe action manager code could return different values.

            • 3. Re: Get layerSet size but ignore Effect layer.
              Jarda Bereza Level 4

              Faster approach would be traverse all layers inside group with AM code get layer bounds and exclude some kind of layers. And then merge your bound with mathematica. (find maximum and minimum value in arrays)

               

              This could be 10-50× faster. Reading descriptors with AM code is pretty fast. Duplicating merging and removing could take 30ms per each action. Properly written AM could do this in less than 5ms.

              I will likely write this code in next days for UnSmart 2.0 script :-)

              • 4. Re: Get layerSet size but ignore Effect layer.
                JJMack Most Valuable Participant

                In your group you have clipped the levels adjustment layer levels 1 to  the shape or smart object layer LAYER.  LAYER has a bounds less than canvas size.  The levels adjustment does not effect the any layers below that layer LAYER because it is clipped to the layer LAYER.  An alternate method  would be instead of clipping the  adjustment layer levels 1 you could mask the adjustment layer to the layer LAYER transparency. You could do the same to the clipped Adjustment levels 1 even.   Either way the bounds of the adjustment layer levels 1 would have the same bounds as layer LAYER.  So would the group.

                • 5. Re: Get layerSet size but ignore Effect layer.
                  Davide_Barranca Level 1

                  Descriptor for the Group has "bounds", "boundsNoEffects" and "boundsNoMask", but each one of them sports the full bound (so in Tomas case 0,0,500,500).

                  No luck!

                   

                  Davide

                  • 6. Re: Get layerSet size but ignore Effect layer.
                    Tomas Sinkunas Level 3

                    JJMack I am having real trouble understanding what you wrote.

                    And Davide Barranca is right, those methods still return same size as the canvas.

                     

                    Jarda Bereza might be on a track of making it work. I thought of traversing all the layers and collecting their bounding box size and then calculating the overall size, but it smells as a hacky way to do so. If it could be done with AM logic, that would be great. However, I am rather new to PSD scripting and I find AM to be rather tricky t get a grasp on.

                     

                    Jarda Bereza if you figure out the way to do that with AM, would you be willing to share your workflow?

                     

                    Thanks.

                    • 7. Re: Get layerSet size but ignore Effect layer.
                      JJMack Most Valuable Participant

                      Let me try a different way  to explain way I wrote and include some screen captures.

                       

                      An adjustment layer bounds is the same as the document canvas size unless masked and applies to all lower layer.  You constrain an adjustment to fewer layer be segregating it within a layer group and clipping it to a particular layer.  You can also constrain the adjustment to a selection via a layer mask.   Transparency can change a layer bounds.  The layer bounds will be the bounds of pixels in the layer mask.

                       

                      To me it looks like you only want the levels adjustment layer to apply to the layer named LAYER.  There are many ways to do that....

                       

                      Here is a little script that show  the active layer size bounds and position relative to the canvas.  I will use it on layer Group see the differences,

                       

                      Capture.jpg

                      // enable double-clicking from Mac Finder or Windows Explorer
                      #target photoshop // this command only works in Photoshop CS2 and higher
                      
                      
                      // bring application forward for double-click events
                      app.bringToFront();
                      
                      
                      // Save the current preferences
                      var startRulerUnits = app.preferences.rulerUnits;
                      // Set Photoshop to use pixels 
                      app.preferences.rulerUnits = Units.PIXELS;
                      
                      
                      try{
                      var LB = activeDocument.activeLayer.bounds;
                      var LWidth = (LB[2].value) - (LB[0].value);
                      var LHeight = (LB[3].value) - (LB[1].value);
                      MarkX((LB[0].value + LWidth/2));
                      MarkX(LB[0].value);
                      MarkX(LB[2].value);
                      MarkY((LB[1].value + LHeight/2));
                      MarkY(LB[1].value)
                      MarkY(LB[3].value)
                      alert("'" + activeDocument.activeLayer.name + "' Layer Bounds\nTop Left " +  LB[0].value + "X," +  LB[1].value + "Y   Bottom Right "  +  LB[2].value + "X," +  LB[3].value
                      + "Y\nWidth " +  LWidth + "px   Height " + LHeight +"px" 
                      + "\nLayer center relative to canvas " + (LB[0].value + LWidth/2) + "X," +  (LB[1].value + LHeight/2) +"Y" 
                      );
                      }
                      catch(e){alert("Requires a layer targered");}
                      
                      
                      // Return the app preferences
                      app.preferences.rulerUnits = startRulerUnits;
                      function MarkX(x) {
                      // =======================================================
                      var idMk = charIDToTypeID( "Mk  " );
                          var desc61 = new ActionDescriptor();
                          var idNw = charIDToTypeID( "Nw  " );
                              var desc62 = new ActionDescriptor();
                              var idPstn = charIDToTypeID( "Pstn" );
                              var idPxl = charIDToTypeID( "#Pxl" );
                              desc62.putUnitDouble( idPstn, idPxl, x);
                              var idOrnt = charIDToTypeID( "Ornt" );
                              var idOrnt = charIDToTypeID( "Ornt" );
                              var idVrtc = charIDToTypeID( "Vrtc" );
                              desc62.putEnumerated( idOrnt, idOrnt, idVrtc );
                          var idGd = charIDToTypeID( "Gd  " );
                          desc61.putObject( idNw, idGd, desc62 );
                      executeAction( idMk, desc61, DialogModes.NO );
                      }
                      function MarkY(y) {
                      // =======================================================
                      var idMk = charIDToTypeID( "Mk  " );
                          var desc63 = new ActionDescriptor();
                          var idNw = charIDToTypeID( "Nw  " );
                              var desc64 = new ActionDescriptor();
                              var idPstn = charIDToTypeID( "Pstn" );
                              var idPxl = charIDToTypeID( "#Pxl" );
                              desc64.putUnitDouble( idPstn, idPxl, y );
                              var idOrnt = charIDToTypeID( "Ornt" );
                              var idOrnt = charIDToTypeID( "Ornt" );
                              var idHrzn = charIDToTypeID( "Hrzn" );
                              desc64.putEnumerated( idOrnt, idOrnt, idHrzn );
                          var idGd = charIDToTypeID( "Gd  " );
                          desc63.putObject( idNw, idGd, desc64 );
                      executeAction( idMk, desc63, DialogModes.NO );
                      }
                      

                      Capture.jpg

                      • 8. Re: Get layerSet size but ignore Effect layer.
                        Jarda Bereza Level 4

                        Try this:

                         

                        Seems to work for me. You will need replace some function from lx. library with your own. But is obvious what it should do.

                        And it should be very very fast. It uses linear layers traversing.

                         

                        #include A:\programovani\PSDmagic\[Lx]\Lexicon-0.1.jsxinc
                        
                        var layerID = lx.getSelectedLayersId();
                        calculateGroupSize(layerID);
                        
                        function calculateGroupSize(layerID){
                                
                            var maxBounds = {
                                    left : null,
                                    top : null,
                                    right : null,
                                    bottom : null
                            }
                            
                            var index = lx.convertLayerIdToIndex(layerID);
                        
                            for(var i = index-1, level=0; level >= 0 ; i--){
                                var desc = lx.getLayerDescriptor(i); // i = index
                                var clipped = desc.getBoolean(stringIDToTypeID('group'));
                                var isAdjustmentLayer = desc.getInteger(stringIDToTypeID('layerKind')) === 2;
                                
                                if(clipped || isAdjustmentLayer){continue;} //skip this layer
                                
                                var layerSection = typeIDToStringID(desc.getEnumerationValue(stringIDToTypeID('layerSection')));
                                if(layerSection==="layerSectionStart"){
                                    level++
                                }
                                else if(layerSection==="layerSectionEnd"){
                                    level--
                                }
                                else{
                                    var bounds = desc.getObjectValue(stringIDToTypeID('bounds'));
                        
                                    if(maxBounds.left === null) {maxBounds.left = bounds.getUnitDoubleValue(stringIDToTypeID('left'));}
                                    if(maxBounds.top === null) {maxBounds.top = bounds.getUnitDoubleValue(stringIDToTypeID('top'));}
                                    if(maxBounds.right === null) {maxBounds.right = bounds.getUnitDoubleValue(stringIDToTypeID('right'));}
                                    if(maxBounds.bottom === null) {maxBounds.left = bounds.getUnitDoubleValue(stringIDToTypeID('bottom'));}
                                       
                                    maxBounds.left = Math.min(maxBounds.left, bounds.getUnitDoubleValue(stringIDToTypeID('left')));
                                    maxBounds.top =  Math.min(maxBounds.top, bounds.getUnitDoubleValue(stringIDToTypeID('top')));
                                    maxBounds.right =  Math.max(maxBounds.right, bounds.getUnitDoubleValue(stringIDToTypeID('right')));
                                    maxBounds.bottom =  Math.max(maxBounds.bottom, bounds.getUnitDoubleValue(stringIDToTypeID('bottom')));
                                }
                            }
                            return maxBounds;
                        }
                        
                        • 9. Re: Get layerSet size but ignore Effect layer.
                          JJMack Most Valuable Participant

                          I do not have your script library files so I can not test that code,  It look like it skips adjustment layers if clipped.  In his layered document it does not look like the  levels 1 adjustment layer is clipped its an adjustment layer above layer LAYER in layer group Group.

                          Screen+Shot+2017-08-04+at+14.09.16.png

                           

                          not

                          Capture.jpg

                          • 10. Re: Get layerSet size but ignore Effect layer.
                            Tomas Sinkunas Level 3

                            That looks interesting, but hard to test without your lx library. Any chance you could share that?

                            • 11. Re: Get layerSet size but ignore Effect layer.
                              Jarda Bereza Level 4

                              Here is code without Lexicon library. I can't share library because is experimental and not done yet.

                              It takes 500ms per 1018 layers. And 77ms per 179 layers on my old PC :-)

                               

                              JJMack: you are wrong. This is "or" condition. I am skiping clipped layer and/or adjustment. Not clipped adjustment.

                               

                               

                              var groupIndex = app.activeDocument.activeLayer.itemIndex;
                              
                              
                              function calculateGroupSize(index){
                                      
                                  var maxBounds = {
                                          left : null,
                                          top : null,
                                          right : null,
                                          bottom : null
                                  }
                              
                              
                                  for(var i = index-1, level=0; level >= 0 ; i--){
                                      var desc = getLayerDescriptor(i); // i = index
                                      var clipped = desc.getBoolean(stringIDToTypeID('group'));
                                      var isAdjustmentLayer = desc.getInteger(stringIDToTypeID('layerKind')) === 2;
                                      
                                      if(clipped || isAdjustmentLayer){continue;} //skip this layer
                                      
                                      var layerSection = typeIDToStringID(desc.getEnumerationValue(stringIDToTypeID('layerSection')));
                                      if(layerSection==="layerSectionStart"){
                                          level++
                                      }
                                      else if(layerSection==="layerSectionEnd"){
                                          level--
                                      }
                                      else{
                                          var bounds = desc.getObjectValue(stringIDToTypeID('bounds'));
                              
                              
                                          if(maxBounds.left === null) {maxBounds.left = bounds.getUnitDoubleValue(stringIDToTypeID('left'));}
                                          if(maxBounds.top === null) {maxBounds.top = bounds.getUnitDoubleValue(stringIDToTypeID('top'));}
                                          if(maxBounds.right === null) {maxBounds.right = bounds.getUnitDoubleValue(stringIDToTypeID('right'));}
                                          if(maxBounds.bottom === null) {maxBounds.left = bounds.getUnitDoubleValue(stringIDToTypeID('bottom'));}
                                             
                                          maxBounds.left = Math.min(maxBounds.left, bounds.getUnitDoubleValue(stringIDToTypeID('left')));
                                          maxBounds.top =  Math.min(maxBounds.top, bounds.getUnitDoubleValue(stringIDToTypeID('top')));
                                          maxBounds.right =  Math.max(maxBounds.right, bounds.getUnitDoubleValue(stringIDToTypeID('right')));
                                          maxBounds.bottom =  Math.max(maxBounds.bottom, bounds.getUnitDoubleValue(stringIDToTypeID('bottom')));
                                          
                                      }
                                  }
                              
                              
                                  return maxBounds;
                              }
                              
                              
                              var getLayerDescriptor = function (index) { //todo reference param
                                  var ref = new ActionReference();  
                                  var idLyr = charIDToTypeID( "Lyr " );
                                          ref.putIndex( idLyr, index ); 
                                  var desc = executeActionGet(ref); 
                                  return desc;
                              }
                              
                              
                              var bounds = calculateGroupSize(groupIndex);
                              alert("\n left: " + bounds.left +"\n top: " + bounds.top +"\n right: " + bounds.right +"\n bottom: " + bounds.bottom);
                              

                               

                              .

                              1 person found this helpful
                              • 12. Re: Get layerSet size but ignore Effect layer.
                                JJMack Most Valuable Participant

                                Yes I do not know javascript so much of the code I do not understand.  I jumped to the wrong conclusion.  Most of the javascript code where I see .getxxx(yyyy) i have to take on faith or guess.  Can't guess right all the time.

                                • 13. Re: Get layerSet size but ignore Effect layer.
                                  Tomas Sinkunas Level 3

                                  Appologies for taking long time to reply Jarda Bereza

                                   

                                  I jumped to conclusion too fast. Script has crashing if I had Background layer in the document. Once I removed it, it seems to work.

                                  Will give more testing to it.

                                   

                                  Thanks man.

                                   

                                  Unfortunately, script crashes on var desc = executeActionGet(ref); with error Error 8800: General Photoshop error occurred. This functionality may not be available in this version of Photoshop. However, I have layerSet "Group" selected in the dome before executing the script.

                                   

                                  Script seems to run fine if I have shape layer selected, but, unfortunately, crashes with layerSet selected.

                                   

                                  Any chance you know why?

                                  • 14. Re: Get layerSet size but ignore Effect layer.
                                    Jarda Bereza Level 4

                                    maybe background layer issue

                                     

                                    increment index by +1 at row 53 if background layer exists.

                                    • 15. Re: Get layerSet size but ignore Effect layer.
                                      Tomas Sinkunas Level 3

                                      yeap, seems as if background layer was messing it up.