21 Replies Latest reply: Mar 6, 2015 4:24 AM by CoenHolten RSS

    PS3 script to batch rename layers

      Sometimes, I make copies of layers (for example: copy little diamonds to align into a shape of the letter M). Each time I "alt+drag" the content in that layer (to make a copy of it), PS makes a copy and then appends the name of the layer to something like "diamond copy 3". After making a ton of copies (and because I'm anal about having actual names for each layer), I want each layer to read "diamond". Instead of manually renaming all these layers, is there a way to highlight the affected layers and choose to rename all layers according to what you want?
        • 1. Re: PS3 script to batch rename layers
          MarkWalsh Community Member
          You're in luck. I just finished writing this yesterday. :)

          This will remove " copy", " copy 1"... etc from all open files. Let me know how it works out for you.

          ///////////////////////////////////////////////////////////////////////////////
          // Script Name: RenameLayers.jsx
          // Version: 1.0
          // Date: 2/27/08
          // Usage: Removes 'copy 1, copy 2, etc' from name of all layers
          ///////////////////////////////////////////////////////////////////////////////

          #target photoshop
          //$.localize = true;
          var displayDialogMode = app.displayDialogs;

          app.bringToFront();
          app.bringToFront();
          app.displayDialogs = DialogModes.NO;

          processObjects(app.documents, processDocument,function () {alert("You have no documents open")})
          app.displayDialogs = displayDialogMode;

          ///////////////////////////////////////////////////////////////////////////////
          // Function: processObjects
          // Usage: Runs theMainFunction on every object in list theObjects
          // Input: List of objects (documents, layers, etc.), Function to run on each object, Function to run on parent if there are no object
          // Return: value returned from function used
          ///////////////////////////////////////////////////////////////////////////////
          function processObjects(theObjects, theMainFunction, theAlternateFunction) {
          var returnValue = null;
          if (theObjects.length ==0) {
          if (!(theAlternateFunction == undefined) && !(theAlternateFunction == null) && !(theAlternateFunction == "")) {
          returnValue = theAlternateFunction (theObjects.parent);
          }
          } else {
          if (!(theMainFunction == undefined) && !(theMainFunction == null) && !(theMainFunction == "")) {
          for (var i = theObjects.length -1; i> -1; i--) {
          returnValue += theMainFunction (theObjects[i], i);
          }
          }
          }
          return returnValue;
          }

          ///////////////////////////////////////////////////////////////////////////////
          // Function: processDocument
          // Usage: Processes layers of document with 'processLayer' function
          // Input: Document object, Document object index
          // Return: none
          ///////////////////////////////////////////////////////////////////////////////
          function processDocument(objectRef, i) {
          app.activeDocument = objectRef
          processObjects(objectRef.layers, processLayer, null);
          }

          ///////////////////////////////////////////////////////////////////////////////
          // Function: processLayer
          // Usage: Removes 'copy' from layer name (processes Layer Set contents)
          // Input: Layer object, Layer Object index
          // Return: none
          ///////////////////////////////////////////////////////////////////////////////
          function processLayer(objectRef, i) {
          if (objectRef.typename == 'LayerSet') {
          var layerCount = processObjects(objectRef.layers, processLayer);
          }
          renameLayer(objectRef)
          return 0
          }

          ///////////////////////////////////////////////////////////////////////////////
          // Function: renameLayer
          // Usage: Removes 'copy' from layer name (processes Layer Set contents)
          // Input: Layer object, Layer Object index
          // Return: none
          ///////////////////////////////////////////////////////////////////////////////
          function renameLayer(objectRef) {
          var theRegEx = new RegExp(/^(.*)(copy(\s(\d)+)*)+$/)
          if (theRegEx.test(objectRef.name)) {
          var indexNumber = 0

          indexnumber = objectRef.name.indexOf(" copy")
          objectRef.name = objectRef.name.substr(0,indexnumber)
          }
          return 0
          }
          • 2. Re: PS3 script to batch rename layers
            Community Member
            Thanks for sharing... now, what do I do with this information?
            • 3. Re: PS3 script to batch rename layers
              MarkWalsh Community Member
              Paste into a text program (notepad on PC, TextEdit on mac) and save into the 'Scripts' directory in the 'Presets' directory of your Photoshop application folder with a '.js' or '.jsx' extension (e.g. "RenameLayers.jsx").

              To activate, select "Scripts" from the"File" menu and select the saved script.
              • 4. Re: PS3 script to batch rename layers
                Community Member
                Thanks... works like a charm. This will save me a lot of time.
                • 5. Re: PS3 script to batch rename layers
                  GagnonEric Community Member
                  Hi!

                  I will surely have a look at the script... Does it handle well hierarchical nested layers?

                  In my current project, i have some documents that are very heavy (by exemple more than 1000 layers!).

                  The automated renaming of around 300 layers in particular document is a process that take as much as 7 hours! (Applescript on a 1.8 G5 computer/4go ram).

                  It's not fully clear to me if it's the logic of the script/the scripting api speed or the heavy use of PSD document that is at fault..

                  If only i had more time for pluggin developpement! :)

                  Eric
                  • 6. Re: PS3 script to batch rename layers
                    MarkWalsh Community Member
                    Yes, it will handle all layers in every layer set. (in every opened file)

                    If you have a lot of layers, it could take a while as it opens each layer set and scrolls through every layer. On the files I've used it on, it runs pretty speedy. I think it will also run much faster than an applescript.
                    • 7. Re: PS3 script to batch rename layers
                      GagnonEric Community Member
                      I have tested it.. it works like advertised (including layers in groups).

                      The script is fast on small sample but get quite slow on heavy documents ... so maybe my problem is more related to document size and maybe not worth investigating other scripting alternatives (but i'm pretty sure that on the same set your script would be faster).

                      The only bug i have found is that the script dont keep track of the visibility of layers. If a layer is invisible (when you do the renaming), the layer should be invisible when you are done with the processing.

                      That "problem" is also visible in a normal user interaction through the interface (select a layer make the layer visible). It's questionable in the user interface and a real problem with automation even if you record and set back the property. It must be clear to the users that if a script is crashing that document need to be reloaded!
                      • 8. Re: PS3 script to batch rename layers
                        MarkWalsh Community Member
                        It looks like changing the name of the layer makes it visible (unless it is the selected layer). I'll see if I can find the time to edit the script to activate each layer before it renames it. This should solve that problem. I'd also like it to restore the state of the layer sets that it opens to select each layer, and if I have it select each layer before renaming, then it should also end with the originally selected layer selected.
                        • 9. Re: PS3 script to batch rename layers
                          GagnonEric Community Member
                          I must say that in my scripts, i had quite a few problems to get around while working with layers! (and not all where solved!)
                          • 10. Re: PS3 script to batch rename layers
                            MarkWalsh Community Member
                            I made a quick rewrite to the renameLayer function. This should fix the problem with invisible layers. I ran the script on a large document just now, and it did take a while (although MUCH faster than would be manually, plus more accurate). It switches to the layer to rename it, and switches back to the original selected layer afterwards. I will rewrite it later to switch to the layer before renaming (hopefully that should solve that slowdown).

                            function renameLayer(objectRef) {
                            var theRegEx = new RegExp(/(\s*copy\s*\d*)+$/)

                            if (theRegEx.test(objectRef.name)) {
                            // save state of layer (visible or invisible)
                            var layerVisible = objectRef.visible
                            var indexNumber = 0
                            indexnumber = objectRef.name.indexOf(" copy")
                            objectRef.name = objectRef.name.substr(0,indexnumber)
                            objectRef.visible = layerVisible
                            }
                            return 0
                            }
                            • 11. Re: PS3 script to batch rename layers
                              matt-dd Community Member

                              Hi Mark,


                              thanks for this, worked a treat and saved me a whole lot of 'fun' in removing copy from each layer.

                              • 12. Re: PS3 script to batch rename layers
                                Mothator

                                Hello Mark,

                                 

                                Also thanks for sharing the script, very usefull. I'm trying to add something to the script so that only selected layers in the document where layers are selected are processed with your renameLayer function. But i can't seem to find the correct code to only get the selected layers and layers sets

                                from this document. Is this even possible to do ? I'm not an experienced coder myself but I can read your script (and write fairly basic scripts). I was trying to fill an array with the selected layer and layer-sets that needed to be renamed, but I even got stuck there.

                                 

                                Thanks,

                                Fred

                                • 13. Re: PS3 script to batch rename layers
                                  Michael L Hale Community Member

                                  Mothator,

                                   

                                  What version of Photoshop are you using. I have a script that removes 'copy' from selected layers but it needs a document descriptor key that is CS4 or higher.

                                  • 14. Re: PS3 script to batch rename layers
                                    Mothator Community Member

                                    I'm using CS4 ...

                                    • 15. Re: PS3 script to batch rename layers
                                      Michael L Hale Community Member

                                      Try this. Just select the layers you want 'copy' removed from and run this script.

                                      if( app.documents.length > 0 ){
                                      app.activeDocument.suspendHistory('Rename selected layers','removeCopyFromSelectedLayersNames()');
                                      }
                                      function removeCopyFromLayerName(){
                                           if( getSelectedLayersIdx().length > 1 ){
                                                var selectedLayers = getSelectedLayersIdx();
                                                makeActiveByIndex( selectedLayers[0], false );
                                           }
                                         var startLoop = Number( !hasBackground() );
                                         var endLoop = getNumberOfLayer() + 1; 
                                         for( var l = startLoop;l < endLoop; l++){
                                              while( !isValidActiveLayer( l ) ) {
                                                  l++;
                                              }
                                                var oldName =  getLayerNameByIndex( l );
                                                var newName = oldName.replace(/\scopy\s?\d*$/i,'');
                                                putLayerNameByIndex( l, newName )
                                           }
                                           if( selectedLayers != undefined ) makeActiveByIndex( selectedLayers, false );
                                      }
                                      function removeCopyFromSelectedLayersNames(){
                                           var selectedLayers = getSelectedLayersIdx();
                                           for( var l = 0;l < selectedLayers.length; l++){
                                                var oldName =  getLayerNameByIndex( selectedLayers[ l ] );
                                                var newName = oldName.replace(/\scopy.*$/i,'');
                                                makeActiveByIndex( selectedLayers[ l ], false );
                                                putLayerNameByIndex( selectedLayers[ l ], newName )
                                           }
                                           makeActiveByIndex( selectedLayers, false );
                                      }
                                      function getNumberOfLayer(){ 
                                      var ref = new ActionReference(); 
                                      ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') ); 
                                      var desc = executeActionGet(ref); 
                                      var numberOfLayer = desc.getInteger(charIDToTypeID('NmbL')); 
                                      return numberOfLayer; 
                                      }
                                      function getLayerNameByIndex( idx ) { 
                                          var ref = new ActionReference(); 
                                          ref.putProperty( charIDToTypeID('Prpr') , charIDToTypeID( 'Nm  ' )); 
                                          ref.putIndex( charIDToTypeID( 'Lyr ' ), idx );
                                          return executeActionGet(ref).getString(charIDToTypeID( 'Nm  ' ));; 
                                      }
                                      function putLayerNameByIndex( idx, name ) {
                                           if( idx == 0 ) return;
                                          var desc = new ActionDescriptor();
                                              var ref = new ActionReference();
                                              ref.putIndex( charIDToTypeID( 'Lyr ' ), idx );
                                          desc.putReference( charIDToTypeID('null'), ref );
                                              var nameDesc = new ActionDescriptor();
                                              nameDesc.putString( charIDToTypeID('Nm  '), name );
                                          desc.putObject( charIDToTypeID('T   '), charIDToTypeID('Lyr '), nameDesc );
                                          executeAction( charIDToTypeID('setd'), desc, DialogModes.NO );
                                      }
                                      function getActiveLayerIndex() {
                                           var ref = new ActionReference();
                                           ref.putProperty( 1349677170 , 1232366921 );
                                           ref.putEnumerated( 1283027488, 1332896878, 1416783732 );
                                           var res = executeActionGet(ref).getInteger( 1232366921 )
                                                                                             - Number( hasBackground() );
                                           return res;   
                                      }
                                      function isValidActiveLayer( idx ) {
                                           var propName = stringIDToTypeID( 'layerSection' );
                                           var ref = new ActionReference(); 
                                           ref.putProperty( 1349677170 , propName);
                                           ref.putIndex( 1283027488, idx );
                                           var desc =  executeActionGet( ref );
                                           var type = desc.getEnumerationValue( propName );
                                           var res = typeIDToStringID( type ); 
                                           return res == 'layerSectionEnd' ? false:true;
                                      }
                                      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;
                                      }
                                      function getSelectedLayersIdx(){
                                           var selectedLayers = new Array;
                                           var ref = new ActionReference();
                                           ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
                                           var desc = executeActionGet(ref);
                                           if( desc.hasKey( stringIDToTypeID( 'targetLayers' ) ) ){
                                                desc = desc.getList( stringIDToTypeID( 'targetLayers' ));
                                                var c = desc.count 
                                                var selectedLayers = new Array();
                                                for(var i=0;i<c;i++){
                                                     selectedLayers.push(  desc.getReference( i ).getIndex());
                                                }
                                           }else{
                                                var ref = new ActionReference(); 
                                                ref.putProperty( charIDToTypeID('Prpr') , charIDToTypeID( 'ItmI' )); 
                                                ref.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
                                                selectedLayers.push( executeActionGet(ref).getInteger(charIDToTypeID( 'ItmI' )));
                                           }
                                           return selectedLayers;
                                      }
                                      function makeActiveByIndex( idx, visible ){
                                           if( idx.constructor != Array ) idx = [ idx ];
                                           for( var i = 0; i < idx.length; i++ ){
                                                var desc = new ActionDescriptor();
                                                var ref = new ActionReference();
                                                ref.putIndex(charIDToTypeID( 'Lyr ' ), idx[i])
                                                desc.putReference( charIDToTypeID( 'null' ), ref );
                                                if( i > 0 ) {
                                                     var idselectionModifier = stringIDToTypeID( 'selectionModifier' );
                                                     var idselectionModifierType = stringIDToTypeID( 'selectionModifierType' );
                                                     var idaddToSelection = stringIDToTypeID( 'addToSelection' );
                                                     desc.putEnumerated( idselectionModifier, idselectionModifierType, idaddToSelection );
                                                }
                                                desc.putBoolean( charIDToTypeID( 'MkVs' ), visible );
                                                executeAction( charIDToTypeID( 'slct' ), desc, DialogModes.NO );
                                           }     
                                      }
                                      
                                      • 16. Re: PS3 script to batch rename layers
                                        Mothator Community Member

                                        Hi Michael,

                                         

                                        It seems to be working perfectly, thanks for sharing this !!

                                         

                                        Greetings,

                                        f,

                                        • 17. Re: PS3 script to batch rename layers
                                          matt-dd Community Member

                                          Hi,

                                           

                                          I copy'n'pasted your script into Text Edit and saved as .jsx, saved that into PS4 > Presets > Scripts and tried it but it didn't work.

                                           

                                          I selected the layer I wanted to remove 'copy' from but got the following error.

                                           

                                          Picture 2.png

                                          Any possible solutions? The initial script at the top of this thread worked, but I have too many layers to work through to use it effectively.

                                           

                                          Any help appreciated.

                                           

                                          --cheers, matt

                                          • 18. Re: PS3 script to batch rename layers
                                            Michael L Hale Community Member

                                            I am not sure why it is not woking for you unless Text Edit did not save it as plain text.

                                             

                                            That script is one of two that I have in a Configurator panel I made. One button removes 'copy' from all layers and the other button removes from selected layers. You can get the panel at http://ps-scripts.com/bb/viewtopic.php?f=10&t=3056

                                            • 19. Re: PS3 script to batch rename layers
                                              matt-dd Community Member

                                              Thanks Michael, that did the trick!

                                               

                                              -matt

                                              • 20. Re: PS3 script to batch rename layers
                                                Joe Seven Community Member

                                                This is very handy, thanks for creating it.

                                                 

                                                Suggestion: It would be very helpful to be able to rename all your selected files in one shot, ie change 25 layers all named "shape 2" to "button".

                                                 

                                                Cheers,

                                                 

                                                J

                                                • 21. Re: PS3 script to batch rename layers
                                                  CoenHolten

                                                  Thanks Michael.

                                                   

                                                  I used your script to replace copy by another word. And it can be recorded too !!!

                                                  Perfect.

                                                   

                                                  Coen