• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

Apply Layer Mask to the Group it is in

Explorer ,
May 01, 2022 May 01, 2022

Copy link to clipboard

Copied

Hi everyone! I'm developing another automation for my work. Everything was correct, but I forgot a variable. Is there any script that can apply the mask that is on the Layer to the group it is in? The layer names will always be the same, as well as their groups.
Thanks for the help!

TOPICS
Actions and scripting , macOS , Windows

Views

568

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Community Expert , May 01, 2022 May 01, 2022

@rrprec – Try this and let me know how you go...

 

EDIT: 3rd May 2022 - Cosmetic changes made to handle edge cases

 

All you need to do is copy the seven steps between the block comments (with or without their associated line comments) into each of the 3 placeholder comments for the other layers. You then only need to change the absolute layer name parameter from "RGBA" to the new child layer name in each case, the rest of the steps are relative.

 

/* RGBA layer set */
// Select the child layer 
...

Votes

Translate

Translate
Adobe
Community Expert ,
May 01, 2022 May 01, 2022

Copy link to clipboard

Copied

Having consistent layer names is useful for automation.

 

Having both unique and consistent layer names are even more useful.

 

This should be simple enough to do with an action, however, having both the layer and set with the same name means that an action does not know when to select the set with the same name as the layer.

 

If the RGBA layer is always positioned as the second layer from the top of the set/group of the same name, then an action can select by relative position 2 layers up (as long as the layers that it traverses are visible).

 

Same for the other named layers, if they are always in the same position in their respective sets, then a relative position layer selection can be made.

 

atn.png

 

Otherwise, a script would be required to select the parent set.

 

Do you know to script?

 

P.S. Do you also wish to remove the layer masks from the original layers after they have been applied to the set/group of the same name?

 

Is this a stand-alone automation, or will it be incorporated into something else?

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
May 01, 2022 May 01, 2022

Copy link to clipboard

Copied

Hi Stephen, Thanks for the reply. It will be a separate automation. The main layers (with the masks), will always be in the same position, but the amount of adjustment layer above them can vary, so I can't do it using actions. And yes, the mask has to be removed from the main layer after being applied to the group. Unfortunately I don't know how to create scripts, I just change some existing ones for my work needs.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 01, 2022 May 01, 2022

Copy link to clipboard

Copied


@rrprec wrote:

Unfortunately I don't know how to create scripts, I just change some existing ones for my work needs.


 

How does it sound if I provide the code to work with the RGBA set, then you can copy it and modify for each of the others?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
May 01, 2022 May 01, 2022

Copy link to clipboard

Copied

That would be great!

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 01, 2022 May 01, 2022

Copy link to clipboard

Copied

I'll post the code later then!

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 01, 2022 May 01, 2022

Copy link to clipboard

Copied

@rrprec – Try this and let me know how you go...

 

EDIT: 3rd May 2022 - Cosmetic changes made to handle edge cases

 

All you need to do is copy the seven steps between the block comments (with or without their associated line comments) into each of the 3 placeholder comments for the other layers. You then only need to change the absolute layer name parameter from "RGBA" to the new child layer name in each case, the rest of the steps are relative.

 

/* RGBA layer set */
// Select the child layer by name, not the parent group of same name
selectLayerName("RGBA");
// Select layer mask channel
selectLayerMaskChannel();
// Load selection from mask channel
selectionFromMask();
// Remove mask from child layer
removeMask();
// Select parent layer set
activeDocument.activeLayer = activeDocument.activeLayer.parent;
// Add mask to set
addMaskFromSelection();
/* RGBA layer set */

/* effectsResult.RGB CC */
// placeholder
/* effectsResult.RGB CC */

/* effectsResult.RGB */
// placeholder
/* effectsResult.RGB */

/* VRayDenoiser.RGB */
// placeholder
/* VRayDenoiser.RGB */


///// Functions /////

function selectLayerName(lyrName) {
    var idselect = stringIDToTypeID("select");
    var desc266 = new ActionDescriptor();
    var idnull = stringIDToTypeID("null");
    var ref59 = new ActionReference();
    var idlayer = stringIDToTypeID("layer");
    ref59.putName(idlayer, lyrName);
    desc266.putReference(idnull, ref59);
    var idmakeVisible = stringIDToTypeID("makeVisible");
    desc266.putBoolean(idmakeVisible, false);
    var idlayerID = stringIDToTypeID("layerID");
    var list41 = new ActionList();
    list41.putInteger(3);
    desc266.putList(idlayerID, list41);
    executeAction(idselect, desc266, DialogModes.NO);
    if (activeDocument.activeLayer.kind === LayerKind.NORMAL) {
    } else {
        app.runMenuItem(stringIDToTypeID('selectNoLayers'));
        alert('Error: No normal layer found!');
    }
}

function selectLayerMaskChannel() {
	var s2t = function (s) {
		return app.stringIDToTypeID(s);
	};
	var descriptor = new ActionDescriptor();
	var reference = new ActionReference();
	reference.putEnumerated( s2t( "channel" ), s2t( "channel" ), s2t( "mask" ));
	descriptor.putReference( s2t( "null" ), reference );
	descriptor.putBoolean( s2t( "makeVisible" ), false );
	executeAction( s2t( "select" ), descriptor, DialogModes.NO );
}

function selectionFromMask() {
	var s2t = function (s) {
		return app.stringIDToTypeID(s);
	};
	var descriptor = new ActionDescriptor();
	var reference = new ActionReference();
	var reference2 = new ActionReference();
	reference.putProperty( s2t( "channel" ), s2t( "selection" ));
	descriptor.putReference( s2t( "null" ), reference );
	reference2.putEnumerated( s2t( "channel" ), s2t( "ordinal" ), s2t( "targetEnum" ));
	descriptor.putReference( s2t( "to" ), reference2 );
	executeAction( s2t( "set" ), descriptor, DialogModes.NO );
}

function removeMask() {
	var s2t = function (s) {
		return app.stringIDToTypeID(s);
	};
	var descriptor = new ActionDescriptor();
	var reference = new ActionReference();
	reference.putEnumerated( s2t( "channel" ), s2t( "ordinal" ), s2t( "targetEnum" ));
	descriptor.putReference( s2t( "null" ), reference );
	executeAction( s2t( "delete" ), descriptor, DialogModes.NO );
}

function addMaskFromSelection() {
	var s2t = function (s) {
		return app.stringIDToTypeID(s);
	};
	var descriptor = new ActionDescriptor();
	var reference = new ActionReference();
	descriptor.putClass( s2t( "new" ), s2t( "channel" ));
	reference.putEnumerated( s2t( "channel" ), s2t( "channel" ), s2t( "mask" ));
	descriptor.putReference( s2t( "at" ), reference );
	descriptor.putEnumerated( s2t( "using" ), s2t( "userMaskEnabled" ), s2t( "revealSelection" ));
	executeAction( s2t( "make" ), descriptor, DialogModes.NO );
}

 

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 01, 2022 May 01, 2022

Copy link to clipboard

Copied

"The main layers (with the masks), will always be in the same position, but the amount of adjustment layer above them can vary, so I can't do it using actions. "

 

Adjustments layer need different input? You can turn on modal control to manually set adjustment while playing action.

 

When it comes to part with mask when layer always have same relative position, select top most layer using shortcut then use shortcut to select layer below before deleting mask. If your layers always have exactly same name then target them by name. In case that layers stack have layers with the same name, action will always select layer which comes first so it is best to have unique layer names.

 

Difficult part is to record action which will work in different situations with different layer naming convention and different order. If you are running action starting from Background layer and controling everythuing then you should not have problem.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 01, 2022 May 01, 2022

Copy link to clipboard

Copied


@Bojan Živković wrote:

In case that layers stack have layers with the same name, action will always select layer which comes first so it is best to have unique layer names.


 

Agreed 100%! This could be easily automated with an action if the layer set was named differently, such as "RGBA-Group" with the layer being named "RGBA", then the action would be able to record the absolute selection of the layer vs. the group, without needing scripting to select the child layers parent group.

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 01, 2022 May 01, 2022

Copy link to clipboard

Copied

The code below would drag a Layer’s Layer Mask to its Group unless it already has a Layer Mask.

Screenshot 2022-05-02 at 08.20.41.pngScreenshot 2022-05-02 at 08.21.52.png

code edited 2022-05-03

 

 

// apply layer mask of layer to group it is situated in if the group has no layer mask;
// 2022, use it at your own risk;
if (app.documents.length > 0) {
var myDocument = app.activeDocument;
var theResults = getLayersAndItsParentsIndexAndID ();
// process;
for (var x = 0; x < theResults.length; x++) {
    var thisOne = theResults[x];
    if (thisOne[0][3] == true && hasLayerMask (thisOne[1][2]) == false) {
        dragLayerMask (thisOne[0][2], thisOne[1][2])
    }
}
};
////////////////////////////////////
function getLayersAndItsParentsIndexAndID () {
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); 
var applicationDesc = executeActionGet(ref);
var theNumber = applicationDesc.getInteger(stringIDToTypeID("numberOfLayers"));
// anumber is intended to keep track of layerset depth;
var aNumber = 0;
var theArray = new Array;
var theGroups = new Array;
////// work through layers //////
for (var m = theNumber; m >= 0; m--) {
try {
var ref = new ActionReference();
ref.putIndex( charIDToTypeID( "Lyr " ), m);
var layerDesc = executeActionGet(ref);
var layerSet = typeIDToStringID(layerDesc.getEnumerationValue(stringIDToTypeID("layerSection")));
var isBackground = layerDesc.getBoolean(stringIDToTypeID("background"));
var theName = layerDesc.getString(stringIDToTypeID('name'));
var theID = layerDesc.getInteger(stringIDToTypeID('layerID'));
var hasLayerMask = layerDesc.hasKey(charIDToTypeID("Usrs"));
var thisArray = [[theName, m, theID, hasLayerMask]];
////////////////////////////////////
// if group start:
if (layerSet == "layerSectionStart" && isBackground != true) {
if (aNumber == 0) {var setArray = [[theName, m, theID, hasLayerMask]]}
else {
// include groups in array;
	for (var o = setArray.length - 1; o >= 0; o--) {thisArray.push(setArray[o])};
//	theArray.push(thisArray);
// set array;
	setArray.push([theName, m, theID, hasLayerMask])
	};
theGroups.push([theName, m, theID, hasLayerMask]);
// add to mark group;
aNumber++
};
// if group end;
if (layerSet == "layerSectionEnd" && isBackground != true) {
// subtract to mark end of group;
aNumber--;
if (aNumber == 0) {var setArray = []}
else {setArray.pop()}
};
// if neither group start or end;
if (layerSet != "layerSectionEnd" && layerSet != "layerSectionStart" && isBackground != true) {
// if anumber is 0 layer is top level;
if (aNumber != 0) {
	for (var o = setArray.length - 1; o >= 0; o--) {thisArray.push(setArray[o])};
	theArray.push(thisArray)
	};
};
////////////////////////////////////
}
catch (e) {};
};
// the results;
return theArray
};
////// based on code by mike hale, via paul riggott //////
function selectLayerByID(id,add){ 
    add = undefined ? add = false:add 
    var ref = new ActionReference();
        ref.putIdentifier(charIDToTypeID("Lyr "), id);
        var desc = new ActionDescriptor();
        desc.putReference(charIDToTypeID("null"), ref );
           if(add) desc.putEnumerated( stringIDToTypeID( "selectionModifier" ), stringIDToTypeID( "selectionModifierType" ), stringIDToTypeID( "addToSelection" ) ); 
          desc.putBoolean( charIDToTypeID( "MkVs" ), false ); 
       try{
        executeAction(charIDToTypeID("slct"), desc, DialogModes.NO );
    }catch(e){
    alert(e.message); 
    }
    };
////// get some stuff from the active layer //////
function getActiveLayerIndex () {
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); 
var layerDesc = executeActionGet(ref);
var theIndex = layerDesc.getInteger(stringIDToTypeID("itemIndex"));
var theSection = typeIDToStringID(layerDesc.getEnumerationValue(stringIDToTypeID("layerSection")));
var hasText = layerDesc.hasKey(stringIDToTypeID("textKey"));
return [theIndex, theSection, hasText]
};
////// move layer mask //////
function dragLayerMask (theLayer, theGroup) {
    try {
    var idchannel = stringIDToTypeID( "channel" );
    var idlayer = stringIDToTypeID( "layer" );
    var idmask = stringIDToTypeID( "mask" );
    var idmake = stringIDToTypeID( "make" );
    var desc12 = new ActionDescriptor();
    var idnew = stringIDToTypeID( "new" );
    desc12.putClass( idnew, idchannel );
    var idat = stringIDToTypeID( "at" );
        var ref5 = new ActionReference();
        ref5.putEnumerated( idchannel, idchannel, idmask );
        ref5.putIdentifier( idlayer, theGroup );
    desc12.putReference( idat, ref5 );
    var idusing = stringIDToTypeID( "using" );
        var ref6 = new ActionReference();
        ref6.putEnumerated( idchannel, idchannel, idmask );
        ref6.putIdentifier( idlayer, theLayer );
    desc12.putReference( idusing, ref6 );
executeAction( idmake, desc12, DialogModes.NO );
// =======================================================
selectLayerByID(theLayer,false);
var iddelete = stringIDToTypeID( "delete" );
    var desc25 = new ActionDescriptor();
    var idnull = stringIDToTypeID( "null" );
        var ref9 = new ActionReference();
        ref9.putEnumerated( idchannel, idchannel, idmask );
        ref6.putIdentifier( idlayer, theLayer );
    desc25.putReference( idnull, ref9 );
executeAction( iddelete, desc25, DialogModes.NO );
    } catch (e) {}
};
////// has layer mask //////
function hasLayerMask (theIdentifier) {
    ref = new ActionReference();
    ref.putProperty (stringIDToTypeID ("property"), charIDToTypeID("Usrs"));
    ref.putIdentifier(charIDToTypeID("Lyr "), theIdentifier);
    var m_Dsc01 = executeActionGet(ref);
    return m_Dsc01.hasKey(charIDToTypeID("Usrs"));
    };

 

 

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 02, 2022 May 02, 2022

Copy link to clipboard

Copied

@c.pfaffenbichler - That's a useful bit of code, skipping over existing layer masks, thank you for sharing.

 

P.S. I just had time to set up a test and I really like how you loop over the layers/sets and compare the names, rather than hard coding in a fixed set of names!

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
May 02, 2022 May 02, 2022

Copy link to clipboard

Copied

Stephen's Code worked perfectly. Really if the groups had different names it would be much easier, but it's something I can't change.
Thanks Stephen and everyone for the help!

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 02, 2022 May 02, 2022

Copy link to clipboard

Copied

@rrprec - I'm glad that you were able to extend the script to the other layers and have a working result.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 03, 2022 May 03, 2022

Copy link to clipboard

Copied

LATEST

Please take a look at the solution offered by @c.pfaffenbichler as it is all automagical!

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines