13 Replies Latest reply: Jul 26, 2013 8:51 AM by Michael L Hale RSS

    Automatically re-link layer masks

    scottyharland6 Community Member

      I was hoping someone might be able to help me with a question regarding linking layer masks. I regularly work on large Photoshop files with many layers and folders within folders and always have the problem moving a folder only to find that somewhere inside there was a layer with an unlinked mask and it gets left behind. Is there a way i can 'relink all layer masks' without having to manually go through and relink them all? Similar to the 'Close all folders' option i guess... Any help would be greatly appreciated.

        • 2. Re: Automatically re-link layer masks
          c.pfaffenbichler Community Member

          This could work for Layer Masks, but not Vector Masks.

          // 2012; use it at your own risk;
          #target photoshop
          if (app.documents.length > 0) {
          linkLayerMasks(app.activeDocument)
          };
          ////// link all layer masks //////
          function linkLayerMasks (theParent) {
                    for (var m = theParent.layers.length - 1; m >= 0;m--) {
                              var theLayer = theParent.layers[m];
                              app.activeDocument.activeLayer = theLayer;
                              var ref = new ActionReference();
                              ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); 
                              var layerDesc = executeActionGet(ref);
                              var layerMaskLinked = layerDesc.getBoolean(layerDesc.getKey(10));
          // link if unlinked;
                              if (layerMaskLinked == false) {
                                        var idsetd = charIDToTypeID( "setd" );
                                                  var desc4 = new ActionDescriptor();
                                                  var idnull = charIDToTypeID( "null" );
                                                            var ref2 = new ActionReference();
                                                            var idLyr = charIDToTypeID( "Lyr " );
                                                            var idOrdn = charIDToTypeID( "Ordn" );
                                                            var idTrgt = charIDToTypeID( "Trgt" );
                                                            ref2.putEnumerated( idLyr, idOrdn, idTrgt );
                                                  desc4.putReference( idnull, ref2 );
                                                  var idT = charIDToTypeID( "T   " );
                                                            var desc5 = new ActionDescriptor();
                                                            var idUsrs = charIDToTypeID( "Usrs" );
                                                            desc5.putBoolean( idUsrs, true );
                                                  var idLyr = charIDToTypeID( "Lyr " );
                                                  desc4.putObject( idT, idLyr, desc5 );
                                        executeAction( idsetd, desc4, DialogModes.NO );
                                        };
          // apply the function to layersets;
                              if (theLayer.typename == "ArtLayer") {}
                              else {
                                        linkLayerMasks(theLayer)
                                        }
                              }
                    };
          
          • 3. Re: Automatically re-link layer masks
            c.pfaffenbichler Community Member

            I guess one could simply add a try-clause with the ScriptingListener-code for linking Vector Masks in the function linkLayerMasks

            • 4. Re: Automatically re-link layer masks
              Paul Riggott Community Member

              Here is another version, this does not open any layersets, and should be faster as it references the layers rather than making active each one.

               

               

              #target photoshop
              app.bringToFront();
              main();
              function main(){
              if(!documents.length) return;
              linkLayers();
              }
              function linkLayers(){ 
                 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;
                      if(desc.hasKey(charIDToTypeID("UsrM"))) link(i);
                          }
              };
              function link(idx){
              var desc = new ActionDescriptor(); 
              var ref = new ActionReference(); 
              ref.putIndex( charIDToTypeID( "Lyr " ), idx ); 
              desc.putReference( charIDToTypeID('null'), ref ); 
              var desc2 = new ActionDescriptor(); 
              desc2.putBoolean( charIDToTypeID('Usrs'), true); 
              desc.putObject( charIDToTypeID('T   '), charIDToTypeID('Lyr '), desc2 ); 
              executeAction( charIDToTypeID('setd'), desc, DialogModes.NO ); 
              };
              
               
              
              • 5. Re: Automatically re-link layer masks
                c.pfaffenbichler Community Member

                Not surprisingly Paul’s Script is neater.

                • 6. Re: Automatically re-link layer masks
                  scottyharland6 Community Member

                  Thanks very much for the help - i'll give it a shot

                  • 7. Re: Automatically re-link layer masks
                    lister110 Community Member

                    Is there a script that also does the Vector mask as well? This is great by the way..

                    • 8. Re: Automatically re-link layer masks
                      Michael L Hale Community Member
                      main();
                      function main(){
                      if(!documents.length) return;
                      linkLayers();
                      }
                      function linkLayers(){ 
                         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;
                              if(desc.hasKey(charIDToTypeID("UsrM"))) linkChannelMask(i);
                              if(desc.getBoolean(stringIDToTypeID("hasVectorMask"))) linkVectorMask(i);
                          }
                      };
                      function linkChannelMask(idx){
                          var desc = new ActionDescriptor(); 
                          var ref = new ActionReference(); 
                          ref.putIndex( charIDToTypeID( "Lyr " ), idx ); 
                          desc.putReference( charIDToTypeID('null'), ref ); 
                          var desc2 = new ActionDescriptor(); 
                          desc2.putBoolean( charIDToTypeID('Usrs'), true); 
                          desc.putObject( charIDToTypeID('T   '), charIDToTypeID('Lyr '), desc2 ); 
                          executeAction( charIDToTypeID('setd'), desc, DialogModes.NO ); 
                      };
                      function linkVectorMask(idx){
                          var desc = new ActionDescriptor();
                              var ref = new ActionReference();
                          ref.putIndex( charIDToTypeID( "Lyr " ), idx ); 
                          desc.putReference( charIDToTypeID( "null" ), ref );
                              var desc1 = new ActionDescriptor();
                              desc1.putBoolean( stringIDToTypeID( "vectorMaskLinked" ), true );
                          desc.putObject( charIDToTypeID( "T   " ), charIDToTypeID( "Lyr " ), desc1 );
                          executeAction( charIDToTypeID( "setd" ), desc, DialogModes.NO );
                      }
                      

                      Adobe has changed both the way masks work and the layer descriptor over the different Photoshop versions. This works in CC. Should work back to at least CS4.

                      • 9. Re: Automatically re-link layer masks
                        lister110 Community Member

                        I ge an error when executing the script (CS6)

                         

                         

                        Error 8500: The requested property does not exist.

                        Line: 19

                        ->          var layerName = desc.getString(charIDToTypeID( 'Nm  ' ));

                         

                         

                        ANy ideas?

                        • 10. Re: Automatically re-link layer masks
                          Michael L Hale Community Member

                          It works for me with CS6( 13.1.2 ). And I thought the layer descriptor has always had a name property. All the way back to Photoshop 7.

                           

                          Does your document have any layerSets? LayerSets should also have that property. But it you are using 13.0 maybe there is a bug. If so I think I know a workaround.

                           

                          Let me know what version you are using and about the layerSets.

                           

                          Just in case, the charID should have two spaces. I don't think that the reason as if it doesn't have the right number of chars you should get a different error.

                          • 11. Re: Automatically re-link layer masks
                            lister110 Community Member

                            Not sure what you mean CS6 13.0

                            screen.png

                            • 12. Re: Automatically re-link layer masks
                              Michael L Hale Community Member

                              I mean what version of CS6 are you using. It has been updated so there are more than one version named CS6. You can find what version you have in the help menu under about Photoshop.

                              • 13. Re: Automatically re-link layer masks
                                Michael L Hale Community Member

                                You could try this. It doesn't use the name property.

                                 

                                main();
                                function main(){
                                if(!documents.length) return;
                                linkLayers();
                                }
                                function linkLayers(){ 
                                   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 layerSection = desc.getEnumerationValue(stringIDToTypeID( 'layerSection'));
                                        var Id = desc.getInteger(stringIDToTypeID( 'layerID' ));
                                        if(typeIDToStringID(layerSection)=='layerSectionEnd') continue;
                                        if(desc.hasKey(charIDToTypeID("UsrM"))) linkChannelMask(i);
                                        if(desc.getBoolean(stringIDToTypeID("hasVectorMask"))) linkVectorMask(i);
                                    }
                                };
                                function linkChannelMask(idx){
                                    var desc = new ActionDescriptor(); 
                                    var ref = new ActionReference(); 
                                    ref.putIndex( charIDToTypeID( "Lyr " ), idx ); 
                                    desc.putReference( charIDToTypeID('null'), ref ); 
                                    var desc2 = new ActionDescriptor(); 
                                    desc2.putBoolean( charIDToTypeID('Usrs'), true); 
                                    desc.putObject( charIDToTypeID('T   '), charIDToTypeID('Lyr '), desc2 ); 
                                    executeAction( charIDToTypeID('setd'), desc, DialogModes.NO ); 
                                };
                                function linkVectorMask(idx){
                                    var desc = new ActionDescriptor();
                                        var ref = new ActionReference();
                                    ref.putIndex( charIDToTypeID( "Lyr " ), idx ); 
                                    desc.putReference( charIDToTypeID( "null" ), ref );
                                        var desc1 = new ActionDescriptor();
                                        desc1.putBoolean( stringIDToTypeID( "vectorMaskLinked" ), true );
                                    desc.putObject( charIDToTypeID( "T   " ), charIDToTypeID( "Lyr " ), desc1 );
                                    executeAction( charIDToTypeID( "setd" ), desc, DialogModes.NO );
                                }