19 Replies Latest reply on Jun 20, 2017 2:35 PM by seguso2

    Export co-ordinates/layer bounds

    Dogspods

      I'm looking for a simple script that will export the coordinates (layer bounds - top left x,y) of the layers to an seperate xml/txt file. I've google searched and the examples i find give far to much info layer height, width, centre, transform point, stack etc which I then have to waste time editing out.

       

      Thanks in advance.

        • 1. Re: Export co-ordinates/layer bounds
          c.pfaffenbichler Level 9

          If they have not been exported as binary you could just edit the recording or writing of that information out in the Scipt itself.

          Could you provide a link to one of those?

          • 2. Re: Export co-ordinates/layer bounds
            Dogspods Level 1

            This is the script I found that kind of gives me what I need, shame there's all the extra info included...

             

             

            //
            // This script exports extended layer.bounds information to [psd_file_name].xml
            // by pattesdours
            //
            
            function docCheck() {
              // ensure that there is at least one document open
              if (!documents.length) {
              alert('There are no documents open.');
              return; // quit
              }
            }
            
            docCheck();
            
            var originalRulerUnits = preferences.rulerUnits;
            preferences.rulerUnits = Units.PIXELS;
            
            var docRef = activeDocument;
            
            var docWidth = docRef.width.value;
            var docHeight = docRef.height.value;
            var mySourceFilePath = activeDocument.fullName.path + "/";
            
            // Code to get layer index / descriptor
            //
            cTID = function(s) { return app.charIDToTypeID(s); };
            sTID = function(s) { return app.stringIDToTypeID(s); };
            function getLayerDescriptor (doc, layer) {
              var ref = new ActionReference();
              ref.putEnumerated(cTID("Lyr "), cTID("Ordn"), cTID("Trgt"));
              return executeActionGet(ref)
            };
            
            function getLayerID(doc, layer) {
              var d = getLayerDescriptor(doc, layer);
              return d.getInteger(cTID('LyrI'));
            };
            
            var stackorder = 0;
            
            // function from Xbytor to traverse all layers
            traverseLayers = function(doc, ftn, reverse) {
              function _traverse(doc, layers, ftn, reverse) {
              var ok = true;
              for (var i = 1; i <= layers.length && ok != false; i++) {
              var index = (reverse == true) ? layers.length-i : i - 1;
              var layer = layers[index];
            
              if (layer.typename == "LayerSet") {
              ok = _traverse(doc, layer.layers, ftn, reverse);
            
              } else {
              stackorder = stackorder + 1;
              ok = ftn(doc, layer, stackorder);
              }
              }
              return ok;
              };
            
              return _traverse(doc, doc.layers, ftn, reverse);
            };
            
            // create a string to hold the data
            var str ="";
            
            // class using a contructor
            function cLayer(doc, layer) {
            
            //this.layerID = Stdlib.getLayerID(doc, layer);
            this.layerID = getLayerID(doc, layer);
              //alert("layer ID: " + this.layerID);
            this.layerWidth = layer.bounds[2].value - layer.bounds[0].value;
              this.layerHeight = layer.bounds[3].value - layer.bounds[1].value;
              
            // these return object coordinates relative to canvas
              this.upperLeftX = layer.bounds[0].value;
              this.upperLeftY = layer.bounds[1].value;
              this.upperCenterX = this.layerWidth / 2 + layer.bounds[0].value;
              this.upperCenterY = layer.bounds[1].value;
              this.upperRightX = layer.bounds[2].value;
              this.upperRightY = layer.bounds[1].value;
              this.middleLeftX = layer.bounds[0].value;
              this.middleLeftY = this.layerHeight / 2 + layer.bounds[1].value;
              this.middleCenterX = this.layerWidth / 2 + layer.bounds[0].value;
              this.middleCenterY = this.layerHeight / 2 + layer.bounds[1].value;
              this.middleRightX = layer.bounds[2].value;
              this.middleRightY = this.layerHeight / 2 + layer.bounds[1].value;
              this.lowerLeftX = layer.bounds[0].value;
              this.lowerLeftY = layer.bounds[3].value;
              this.lowerCenterX = this.layerWidth / 2 + layer.bounds[0].value;
              this.lowerCenterY = layer.bounds[3].value;
              this.lowerRightX = layer.bounds[2].value;
              this.lowerRightY = layer.bounds[3].value;
            
            // I'm adding these for easier editing of flash symbol transformation point (outputs a 'x, y' format)
            // because I like to assign shortcut keys that use the numeric pad keyboard, like such:
            // 7 8 9
            // 4 5 6
            // 1 2 3
            //
            this.leftBottom = this.lowerLeftX + ", " + this.lowerLeftY;
            this.bottomCenter = this.lowerCenterX + ", " + this.lowerCenterY;
            this.rightBottom = this.lowerRightX + ", " + this.lowerRightY;
            
            this.leftCenter = this.middleLeftX + ", " + this.middleLeftY;
            this.center = this.middleCenterX + ", " + this.middleCenterY;
            this.rightCenter = this.middleRightX + ", " + this.middleRightY;
            
            this.leftTop = this.upperLeftX + ", " + this.upperLeftY;
            this.topCenter = this.upperCenterX + ", " + this.upperCenterY;
            this.rightTop = this.upperRightX + ", " + this.upperRightY;
            
            // these return object coordinates relative to layer bounds
              this.relUpperLeftX = layer.bounds[1].value - layer.bounds[1].value;
              this.relUpperLeftY = layer.bounds[0].value - layer.bounds[0].value;
              this.relUpperCenterX = this.layerWidth / 2;
              this.relUpperCenterY = layer.bounds[0].value - layer.bounds[0].value;
              this.relUpperRightX = this.layerWidth;
              this.relUpperRightY = layer.bounds[0].value - layer.bounds[0].value;
              this.relMiddleLeftX = layer.bounds[1].value - layer.bounds[1].value;
              this.relMiddleLeftY = this.layerHeight / 2;
              this.relMiddleCenterX = this.layerWidth / 2;
              this.relMiddleCenterY = this.layerHeight / 2;
              this.relMiddleRightX = this.layerWidth;
            this.relMiddleRightY = this.layerHeight / 2;
              this.relLowerLeftX = layer.bounds[1].value - layer.bounds[1].value;
              this.relLowerLeftY = this.layerHeight;
              this.relLowerCenterX = this.layerWidth / 2;
            this.relLowerCenterY = this.layerHeight / 2;
              this.relLowerRightY = this.layerHeight;
              this.relLowerRightX = this.layerWidth;
              this.relLowerRightY = this.layerHeight;
              
              return this;
            }
            
            // add header line
            str = "<psd filename=\"" + docRef.name + "\" path=\"" + mySourceFilePath + "\" width=\"" + docWidth + "\" height=\"" + docHeight + "\">\n";
            
            // now a function to collect the data
            function exportBounds(doc, layer, i) {
              var isVisible = layer.visible;
              var layerData = cLayer(doc, layer);
            
              if(isVisible){
            // Layer object main coordinates relative to its active pixels
              var str2 = "\t<layer name=\"" + layer.name 
            + "\" stack=\"" + (i - 1) // order in which layers are stacked, starting with zero for the bottom-most layer
            + "\" position=\"" + leftTop // this is the 
            + "\" layerwidth=\"" + layerData.layerWidth 
            + "\" layerheight=\"" + layerData.layerHeight 
            + "\" transformpoint=\"" + "center" + "\">" // hard-coding 'center' as the default transformation point
            + layer.name + ".png" + "</layer>\n" // I have to put some content here otherwise sometimes tags are ignored
            str += str2.toString();
              };
            };
            
            
            // call X's function using the one above
            traverseLayers(app.activeDocument, exportBounds, true);
            
            // Use this to export XML file to same directory where PSD file is located
              var mySourceFilePath = activeDocument.fullName.path + "/";
            // create a reference to a file for output
              var csvFile = new File(mySourceFilePath.toString().match(/([^\.]+)/)[1] + app.activeDocument.name.match(/([^\.]+)/)[1] + ".xml");
            // open the file, write the data, then close the file
            csvFile.open('w');
            csvFile.writeln(str + "</psd>");
            csvFile.close();
            preferences.rulerUnits = originalRulerUnits;
            // Confirm that operation has completed
            alert("Operation Complete!" + "\n" + "Layer coordinates were successfully exported to:" + "\n" + "\n" + mySourceFilePath.toString().match(/([^\.]+)/)[1] + app.activeDocument.name.match(/([^\.]+)/)[1] + ".xml");
            
            

             

            I don't really want to have to go back into the xml and edit any results as there's usually 75+ items.

            • 3. Re: Export co-ordinates/layer bounds
              Paul Riggott Level 6

              This will write the layer name and x, y to a text file on the desktop.

               

               

              #target photoshop
              main();
              function main(){
              if(!documents.length) return;
              var Info = getNamesPlusIDs().sort();
              var Name = app.activeDocument.name.replace(/\.[^\.]+$/, '');
              var file = new File(Folder.desktop + "/" + Name + ".txt");
              file.open("w", "TEXT", "????");
              $.os.search(/windows/i)  != -1 ? file.lineFeed = 'windows'  : file.lineFeed = 'macintosh';
              for(var a in Info) file.writeln(Info[a].toString());
              file.close();
              }
              function getNamesPlusIDs(){ 
                 var ref = new ActionReference(); 
                 ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') ); 
                 var count = executeActionGet(ref).getInteger(charIDToTypeID('NmbL')) +1; 
                 var Names=[];
              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 vMask = desc.getBoolean(stringIDToTypeID('hasVectorMask' )); 
                  try{
                    var adjust = typeIDToStringID(desc.getList (stringIDToTypeID('adjustment')).getClass (0));
                    if(vMask == true){
                        adjust = false;
                        var Shape = true;
                        }
                    }catch(e){var adjust = false; var Shape = false;}
                      var layerType = typeIDToStringID(desc.getEnumerationValue( stringIDToTypeID( 'layerSection' )));
                      var isLayerSet =( layerType == 'layerSectionContent') ? false:true;
                      var Vis = desc.getBoolean(stringIDToTypeID( 'visible' )); 
                      var descBounds = executeActionGet(ref).getObjectValue(stringIDToTypeID( "bounds" ));
                      var X = descBounds.getUnitDoubleValue(stringIDToTypeID('left'));
                      var Y = descBounds.getUnitDoubleValue(stringIDToTypeID('top'));
                      if(Vis && !isLayerSet && !adjust) Names.push([[layerName],[X],[Y]]);
                 }; 
              return Names;
              };
              
              
              • 4. Re: Export co-ordinates/layer bounds
                Dogspods Level 1

                ...that is exactly what i was looking for - thanks very much Paul

                • 5. Re: Export co-ordinates/layer bounds
                  Dogspods Level 1

                  BUT! Can I be really pedantic and ask for the results to be shown as:

                   

                  Layer Name - x123, y456

                   

                  (123 + 456 used for example only)

                  • 6. Re: Export co-ordinates/layer bounds
                    Paul Riggott Level 6

                    Here you are...

                     

                     

                    #target photoshop
                    main();
                    function main(){
                    if(!documents.length) return;
                    var Info = getNamesPlusIDs().sort();
                    var Name = app.activeDocument.name.replace(/\.[^\.]+$/, '');
                    var file = new File(Folder.desktop + "/" + Name + ".txt");
                    file.open("w", "TEXT", "????");
                    $.os.search(/windows/i)  != -1 ? file.lineFeed = 'windows'  : file.lineFeed = 'macintosh';
                    for(var a in Info) file.writeln(Info[a][0] +"-x"+Info[a][1]+",y"+Info[a][2]);
                    file.close();
                    }
                    function getNamesPlusIDs(){ 
                       var ref = new ActionReference(); 
                       ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') ); 
                       var count = executeActionGet(ref).getInteger(charIDToTypeID('NmbL')) +1; 
                       var Names=[];
                    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 vMask = desc.getBoolean(stringIDToTypeID('hasVectorMask' )); 
                        try{
                          var adjust = typeIDToStringID(desc.getList (stringIDToTypeID('adjustment')).getClass (0));
                          if(vMask == true){
                              adjust = false;
                              var Shape = true;
                              }
                          }catch(e){var adjust = false; var Shape = false;}
                            var layerType = typeIDToStringID(desc.getEnumerationValue( stringIDToTypeID( 'layerSection' )));
                            var isLayerSet =( layerType == 'layerSectionContent') ? false:true;
                            var Vis = desc.getBoolean(stringIDToTypeID( 'visible' )); 
                            var descBounds = executeActionGet(ref).getObjectValue(stringIDToTypeID( "bounds" ));
                            var X = descBounds.getUnitDoubleValue(stringIDToTypeID('left'));
                            var Y = descBounds.getUnitDoubleValue(stringIDToTypeID('top'));
                            if(Vis && !isLayerSet && !adjust) Names.push([[layerName],[X],[Y]]);
                       }; 
                    return Names;
                    };
                    
                     
                    
                    2 people found this helpful
                    • 7. Re: Export co-ordinates/layer bounds
                      Dogspods Level 1

                      ...one final question (promise!) is there a reason why the co-ords are shown on the txt file alphabetically and not as layer order?

                      • 8. Re: Export co-ordinates/layer bounds
                        Paul Riggott Level 6

                        Yes, change line :-

                        var Info = getNamesPlusIDs().sort();
                        

                        to

                        var Info = getNamesPlusIDs();
                        

                         

                        then they should be in layer order.

                        • 9. Re: Export co-ordinates/layer bounds
                          Ferb111184

                          Is there a way to create a XML file with folders included?

                           

                          <psd>

                          <layer></layer>

                          <layer></layer>

                          <folder>

                          <layer></layer>

                          </folder

                          </psd>

                          • 10. Re: Export co-ordinates/layer bounds
                            mraj32

                            Capture.PNG

                            Script is working fine for image coordinates but When i try to extract the layer position i am not getting extract position from psd. can you help me getting correct data from psd. attached is the value expected'default text layer' as 43, 60.77 but i am getting different position. Advance thanks

                            • 11. Re: Export co-ordinates/layer bounds
                              wilbirita78496655

                              can i use this script in illustrator?

                              • 12. Re: Export co-ordinates/layer bounds
                                chrisk82345302

                                Hi Paul,

                                 

                                Great Script. One additional question though. I'd like to include the rotation (transform) of my smart objects in the exported .txt file. I found a script that suppose to work, but I cannot get it to work (with to your script). Any thoughts or examples how to best make this work?

                                 

                                ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

                                function angleFromMatrix(yy, xy)

                                {

                                  var toDegs = 180/Math.PI;

                                  return Math.atan2(yy, xy) * toDegs - 90;

                                }

                                 

                                 

                                function getActiveLayerRotation()

                                {

                                  var ref = new ActionReference();

                                  ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );

                                  var desc = executeActionGet(ref).getObjectValue(stringIDToTypeID('textKey'))

                                  if (desc.hasKey(stringIDToTypeID('transform')))

                                  {

                                  desc = desc.getObjectValue(stringIDToTypeID('transform'))

                                  var yy = desc.getDouble(stringIDToTypeID('yy'));

                                  var xy = desc.getDouble(stringIDToTypeID('xy'));

                                  return angleFromMatrix(yy, xy);

                                  }

                                  return 0;

                                }

                                ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

                                • 13. Re: Export co-ordinates/layer bounds
                                  JJMack Most Valuable Participant

                                  Paul left years ago the append you appeded to is three years old.  The function you posted is for text layers not other layer types.

                                  • 14. Re: Export co-ordinates/layer bounds
                                    seguso2

                                    This script works, and I extended it to also export width and height of the layer in addition to the layer x,y coordinates (see below) .

                                     

                                    The problem is that it does not work with groups, only with single layers. I have groups I am exporting with the asset generator, and I need to know at what position to place them in my app. I don't know how to change the script to work with groups. Can somebody help?

                                     

                                    Here is my modified script that exports width and height:

                                     

                                    #target photoshop

                                    main();

                                    function main(){

                                    if(!documents.length) return;

                                    var Info = getNamesPlusIDs().sort();

                                    var Name = app.activeDocument.name.replace(/\.[^\.]+$/, '');

                                    var path = app.activeDocument.path;

                                    var file = new File(path + "/" + Name + "-coords.txt");

                                    file.open("w", "TEXT", "????");

                                    $.os.search(/windows/i)  != -1 ? file.lineFeed = 'windows'  : file.lineFeed = 'macintosh';

                                    for(var a in Info) file.writeln(Info[a][0] +"---x"+Info[a][1]+",y"+Info[a][2] + ",w" + Info[a][3]+ ",h" + Info[a][4]);

                                    file.close();

                                    }

                                    function getNamesPlusIDs(){

                                      var ref = new ActionReference();

                                      ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );

                                      var count = executeActionGet(ref).getInteger(charIDToTypeID('NmbL')) +1;

                                      var Names=[];

                                    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 vMask = desc.getBoolean(stringIDToTypeID('hasVectorMask' ));

                                        try{

                                          var adjust = typeIDToStringID(desc.getList (stringIDToTypeID('adjustment')).getClass (0));

                                          if(vMask == true){

                                              adjust = false;

                                              var Shape = true;

                                              }

                                          }catch(e){var adjust = false; var Shape = false;}

                                            var layerType = typeIDToStringID(desc.getEnumerationValue( stringIDToTypeID( 'layerSection' )));

                                            var isLayerSet =( layerType == 'layerSectionContent') ? false:true;

                                            var Vis = desc.getBoolean(stringIDToTypeID( 'visible' ));

                                            var descBounds = executeActionGet(ref).getObjectValue(stringIDToTypeID( "bounds" ));

                                            var X = descBounds.getUnitDoubleValue(stringIDToTypeID('left'));

                                            var Y = descBounds.getUnitDoubleValue(stringIDToTypeID('top'));

                                      var Wt = descBounds.getUnitDoubleValue(stringIDToTypeID('width'));

                                      var Ht = descBounds.getUnitDoubleValue(stringIDToTypeID('height'));

                                            if(Vis && !isLayerSet && !adjust) Names.push([[layerName],[X],[Y], [Wt], [Ht]]);

                                      };

                                    return Names;

                                    };

                                    • 15. Re: Export co-ordinates/layer bounds
                                      JJMack Most Valuable Participant

                                      You would need to recursively process all the layer in your document and write out a record for each layer noting the group it is in its layer name more then one layer can have the same name record each layer size and location in its record. Groups can be nested if you have nested groups the group name need to handle nesting of groups.

                                      1 person found this helpful
                                      • 16. Re: Export co-ordinates/layer bounds
                                        seguso2 Level 1

                                        Thank you. I was wondering if there's a simpler alternative... could we have a script that merges all (toplevel) groups separately?

                                        • 17. Re: Export co-ordinates/layer bounds
                                          JJMack Most Valuable Participant

                                          You could code that you just would not process groups that are nested in a group.  All layers in nested groups would simply not be processed. Layers outside of Groups and Layers in top level groups would be processed.

                                          • 18. Re: Export co-ordinates/layer bounds
                                            nvega

                                            Hi seguso2, I've been trying to use your extended script, but I'm getting an Error 8800 at line 44. Can you recommend something I do to fix the error?

                                            • 19. Re: Export co-ordinates/layer bounds
                                              seguso2 Level 1

                                              Sorry, I have no idea. It works for me on Photoshop 2015 and 2017.