Skip navigation
scottyharland6
Currently Being Moderated

Automatically re-link layer masks

Aug 17, 2012 6:22 AM

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.

 
Replies
  • Currently Being Moderated
    Aug 17, 2012 7:21 AM   in reply to scottyharland6
     
    |
    Mark as:
  • Currently Being Moderated
    Aug 17, 2012 8:00 AM   in reply to scottyharland6

    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)
                                  }
                        }
              };
    
     
    |
    Mark as:
  • Currently Being Moderated
    Aug 17, 2012 8:18 AM   in reply to scottyharland6

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

     
    |
    Mark as:
  • Currently Being Moderated
    Aug 17, 2012 9:21 AM   in reply to scottyharland6

    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 ); 
    };
    
     
    
     
    |
    Mark as:
  • Currently Being Moderated
    Aug 18, 2012 3:25 AM   in reply to Paul Riggott

    Not surprisingly Paul’s Script is neater.

     
    |
    Mark as:
  • Currently Being Moderated
    Jul 25, 2013 9:49 AM   in reply to scottyharland6

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

     
    |
    Mark as:
  • Currently Being Moderated
    Jul 25, 2013 10:36 AM   in reply to lister110
    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.

     
    |
    Mark as:
  • Currently Being Moderated
    Jul 25, 2013 2:16 PM   in reply to Michael L Hale

    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?

     
    |
    Mark as:
  • Currently Being Moderated
    Jul 25, 2013 3:46 PM   in reply to lister110

    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.

     
    |
    Mark as:
  • Currently Being Moderated
    Jul 25, 2013 3:55 PM   in reply to Michael L Hale

    Not sure what you mean CS6 13.0

    screen.png

     
    |
    Mark as:
  • Currently Being Moderated
    Jul 25, 2013 4:00 PM   in reply to lister110

    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.

     
    |
    Mark as:
  • Currently Being Moderated
    Jul 26, 2013 8:51 AM   in reply to lister110

    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 );
    }
    
     
    |
    Mark as:

More Like This

  • Retrieving data ...

Bookmarked By (0)

Answers + Points = Status

  • 10 points awarded for Correct Answers
  • 5 points awarded for Helpful Answers
  • 10,000+ points
  • 1,001-10,000 points
  • 501-1,000 points
  • 5-500 points