Skip to main content
Participating Frequently
March 1, 2016
Answered

Group layer mask feather

  • March 1, 2016
  • 1 reply
  • 698 views

I'm writing a script that iterates through a document's layers and applies a mask feather if there isn't already one. 

var iterGroup = function(group){

    for(i=0; i<group.layerSets.length; i++){

        iterGroup(group.layerSets);

    };

    for(i=0; i<group.artLayers.length; i++){

        if(group.artLayers.layerMaskFeather == 0){

            //Try clause because script crashes on layers that have no mask.

            try{

                group.artLayers.layerMaskFeather = 0.5;

            }catch(err){

            };

        };

    };

};

iterGroup(app.activeDocument);

It does what it's supposed to do, kind of, but it only works on art layers.  The big frustration I have is that we use a lot of masks on group layers, and for some reason Adobe chose to put the layerMaskFeather property in the artLayer class rather than its parent class, the layer.  The layerset class seems to have no DOM access to the layerMaskFeather property, even though it's available from the GUI.  I could also select each layer in turn and run an action on it, but I still need to sample the mask feather to see if the user already has a custom setting.  Is there any way I can do this? 

Thanks,

-Tim

This topic has been closed for replies.
Correct answer SuperMerlin

This will do a full psd.

#target photoshop;

if(documents.length) userMaskFeatherIfZero();

function userMaskFeatherIfZero(){

   var ref = new ActionReference();

   ref.putProperty( charIDToTypeID( "Prpr" ), charIDToTypeID( 'NmbL' ));

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

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

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

        if(layerName.match(/^<\/Layer group/) ) continue;

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

                if(desc.hasKey(charIDToTypeID('Usrs'))){

                    if(desc.getDouble(stringIDToTypeID( 'userMaskFeather' )) == 0){

                        userMaskFeather(i,0.5);

                        }

            }

   };

};

function userMaskFeather(Index,amount) {

var desc = new ActionDescriptor();

var ref = new ActionReference();

ref.putIndex( charIDToTypeID( 'Lyr ' ), Index);

desc.putReference( charIDToTypeID('null'), ref );

var desc2 = new ActionDescriptor();

desc2.putUnitDouble( stringIDToTypeID('userMaskFeather'), charIDToTypeID('#Pxl'), amount);

desc.putObject( charIDToTypeID('T   '), charIDToTypeID('Lyr '), desc2 );

try{

executeAction( charIDToTypeID('setd'), desc, DialogModes.NO );

}catch(e){}

};

1 reply

SuperMerlin
SuperMerlinCorrect answer
Inspiring
March 1, 2016

This will do a full psd.

#target photoshop;

if(documents.length) userMaskFeatherIfZero();

function userMaskFeatherIfZero(){

   var ref = new ActionReference();

   ref.putProperty( charIDToTypeID( "Prpr" ), charIDToTypeID( 'NmbL' ));

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

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

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

        if(layerName.match(/^<\/Layer group/) ) continue;

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

                if(desc.hasKey(charIDToTypeID('Usrs'))){

                    if(desc.getDouble(stringIDToTypeID( 'userMaskFeather' )) == 0){

                        userMaskFeather(i,0.5);

                        }

            }

   };

};

function userMaskFeather(Index,amount) {

var desc = new ActionDescriptor();

var ref = new ActionReference();

ref.putIndex( charIDToTypeID( 'Lyr ' ), Index);

desc.putReference( charIDToTypeID('null'), ref );

var desc2 = new ActionDescriptor();

desc2.putUnitDouble( stringIDToTypeID('userMaskFeather'), charIDToTypeID('#Pxl'), amount);

desc.putObject( charIDToTypeID('T   '), charIDToTypeID('Lyr '), desc2 );

try{

executeAction( charIDToTypeID('setd'), desc, DialogModes.NO );

}catch(e){}

};

Participating Frequently
March 2, 2016

This works brilliantly!  I am curious, though, how you came to a lot of that code.  I understand a lot of the action descriptor stuff was probably auto-generated by the script listener, but I don't understand how you modified it to grab values rather than change them. 

SuperMerlin
Inspiring
March 2, 2016

It's done by examining the layer descriptor.

Here is an example script writen by Christoph Pfaffenbichler.

It needs to be run fron ExtendScript Toolkit.

//Written by Christoph Pfaffenbichler

// based on code by michael l hale;

// 2012, use it at your own risk;

#target photoshop

var ref = new ActionReference();

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

var applicationDesc = executeActionGet(ref);

checkDesc2(applicationDesc);

function checkDesc2 (aDesc) {

var c = aDesc.count;

var str = '';

for(var i=0;i<c;i++){ //enumerate descriptor's keys

          str = str + 'Key '+i+' = '+typeIDToStringID(aDesc.getKey(i))+': '+aDesc.getType(aDesc.getKey(i))+'\n'+getValues (aDesc, i)+'\n';

          };

$.writeln("desc\n\n"+str);

};

////// check //////

function getValues (aDesc, aNumber) {

switch (aDesc.getType(aDesc.getKey(aNumber))) {

case DescValueType.BOOLEANTYPE:

return aDesc.getBoolean(aDesc.getKey(aNumber));

break;

case DescValueType.CLASSTYPE:

return aDesc.getClass(aDesc.getKey(aNumber));

break;

case DescValueType.DOUBLETYPE:

return aDesc.getDouble(aDesc.getKey(aNumber));

break;

case DescValueType.ENUMERATEDTYPE:

return (typeIDToStringID(aDesc.getEnumerationValue(aDesc.getKey(aNumber)))+"_"+typeIDToStringID(aDesc.getEnumerationType(aDesc.getKey(aNumber))));

break;

case DescValueType.INTEGERTYPE:

return aDesc.getInteger(aDesc.getKey(aNumber));

break;

case DescValueType.LISTTYPE:

return aDesc.getList(aDesc.getKey(aNumber));

break;

case DescValueType.OBJECTTYPE:

return (aDesc.getObjectValue(aDesc.getKey(aNumber))+"_"+typeIDToStringID(aDesc.getObjectType(aDesc.getKey(aNumber))));

break;

case DescValueType.REFERENCETYPE:

return aDesc.getReference(aDesc.getKey(aNumber));

break;

case DescValueType.STRINGTYPE:

return aDesc.getString(aDesc.getKey(aNumber));

break;

case DescValueType.UNITDOUBLE:

return (aDesc.getUnitDoubleValue(aDesc.getKey(aNumber))+"_"+typeIDToStringID(aDesc.getUnitDoubleType(aDesc.getKey(aNumber))));

break;

default:

break;

};

};