Skip to main content
Participant
August 17, 2012
Question

Automatically re-link layer masks

  • August 17, 2012
  • 5 replies
  • 4576 views

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.

This topic has been closed for replies.

5 replies

Participant
August 20, 2012

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

Inspiring
July 25, 2013

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

Inspiring
July 25, 2013

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.

Paul Riggott
Inspiring
August 17, 2012

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 );
};


c.pfaffenbichler
Community Expert
Community Expert
August 18, 2012

Not surprisingly Paul’s Script is neater.

c.pfaffenbichler
Community Expert
Community Expert
August 17, 2012

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

c.pfaffenbichler
Community Expert
Community Expert
August 17, 2012

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;

                    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)

                              }

                    }

          };

c.pfaffenbichler
Community Expert
Community Expert
August 17, 2012