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

Help with Action Manager - Fill a layer mask with black by ID without activating it

Explorer ,
Apr 02, 2020 Apr 02, 2020

It's being really hard to understand Action Manager, but I'm trying and I need some help to make this work.
I want to fill a layer mask remotelly, by ID, without having to select the layer.

This is the code I'm trying to create:

 

function fillWithBlack(ID) {
	var desc = new ActionDescriptor();
		var ref = new ActionReference();
		ref.putEnumerated( stringIDToTypeID('channel'), stringIDToTypeID('channel'), stringIDToTypeID('mask') );
		ref.putIdentifier(stringIDToTypeID( 'layer' ), ID);
	desc.putReference( stringIDToTypeID('null'), ref );
	desc.putBoolean( stringIDToTypeID('makeVisible'), false );
	desc.putEnumerated( stringIDToTypeID('using'), stringIDToTypeID('fillContents'), stringIDToTypeID('black') );
	desc.putUnitDouble( stringIDToTypeID('opacity'), stringIDToTypeID('percentUnit'), 100.000000 );
	desc.putEnumerated( stringIDToTypeID('mode'), stringIDToTypeID('blendMode'), stringIDToTypeID('normal') );
	desc.putReference( stringIDToTypeID( 'at' ), ref );
	executeAction( stringIDToTypeID('fill'), desc, DialogModes.NO );
}

 

TOPICS
Actions and scripting
1.4K
Translate
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
Adobe
Community Expert ,
Apr 02, 2020 Apr 02, 2020

Your using Action manager code. As far as I know Actions steps work on the active layer you are most likely passing the function a layer object which is made the active layer and the mask filled  by the action manager code. You would need to write the DOM code to fill a layer's Mask with black by layer ID.

 

 

When I use the scriplistener to record filling a mask with black it recorde two steps first one select the layer mask the second one fill the mask.

// =======================================================
var idslct = charIDToTypeID( "slct" );
var desc13 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref7 = new ActionReference();
var idChnl = charIDToTypeID( "Chnl" );
var idChnl = charIDToTypeID( "Chnl" );
var idMsk = charIDToTypeID( "Msk " );
ref7.putEnumerated( idChnl, idChnl, idMsk );
var idLyr = charIDToTypeID( "Lyr " );
ref7.putName( idLyr, "Layer 2" );
desc13.putReference( idnull, ref7 );
var idMkVs = charIDToTypeID( "MkVs" );
desc13.putBoolean( idMkVs, false );
executeAction( idslct, desc13, DialogModes.NO );

// =======================================================
var idFl = charIDToTypeID( "Fl " );
var desc17 = new ActionDescriptor();
var idUsng = charIDToTypeID( "Usng" );
var idFlCn = charIDToTypeID( "FlCn" );
var idBlck = charIDToTypeID( "Blck" );
desc17.putEnumerated( idUsng, idFlCn, idBlck );
var idOpct = charIDToTypeID( "Opct" );
var idPrc = charIDToTypeID( "#Prc" );
desc17.putUnitDouble( idOpct, idPrc, 100.000000 );
var idMd = charIDToTypeID( "Md " );
var idBlnM = charIDToTypeID( "BlnM" );
var idNrml = charIDToTypeID( "Nrml" );
desc17.putEnumerated( idMd, idBlnM, idNrml );
executeAction( idFl, desc17, DialogModes.NO );

 

// =======================================================
select(false);
function select(makeVisible) {
	var descriptor = new ActionDescriptor();
	var reference = new ActionReference();

	reference.putEnumerated( stringIDToTypeID( "channel" ), stringIDToTypeID( "channel" ), stringIDToTypeID( "mask" ));
	reference.putName( stringIDToTypeID( "layer" ), "Layer 2" );
	descriptor.putReference( charIDToTypeID( "null" ), reference );
	descriptor.putBoolean( stringIDToTypeID( "makeVisible" ), makeVisible );
	executeAction( stringIDToTypeID( "select" ), descriptor, DialogModes.NO );
}

// =======================================================
fill(100);
function fill(opacity) {
	var descriptor = new ActionDescriptor();

	descriptor.putEnumerated( stringIDToTypeID( "using" ), stringIDToTypeID( "fillContents" ), stringIDToTypeID( "black" ));
	descriptor.putUnitDouble( stringIDToTypeID( "opacity" ), stringIDToTypeID( "percentUnit" ), opacity );
	descriptor.putEnumerated( stringIDToTypeID( "mode" ), stringIDToTypeID( "blendMode" ), stringIDToTypeID( "normal" ));
	executeAction( stringIDToTypeID( "fill" ), descriptor, DialogModes.NO );
}

 

Your code seems to combine the two steps targeting the layer mask and filling it with black. Targeting the Layer Mask make the layer the active layer.

 

 

You could save the active layer in variable the use your action manager function then restore the active layer using your saved variable.

JJMack
Translate
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 ,
Apr 02, 2020 Apr 02, 2020

JJMack, you are right. I was trying to combine both tasks in one script.
Thanks

Translate
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
Mentor ,
Apr 02, 2020 Apr 02, 2020

Unfortunately, Action Manager in most cases does not allow working with the contents of a layer without activating it. For example, I can easily remove the layer mask without making it active (in example layerID = 2), but I can’t create a new mask in the same way - it will be created only for the active layer

 

s2t = stringIDToTypeID;

(ref = new ActionReference()).putEnumerated( s2t( "channel" ), s2t( "channel" ), s2t( "mask" ));
(desc = new ActionDescriptor()).putReference( s2t( "null" ), ref );
(ref2 = new ActionReference()).putEnumerated( s2t('channel'), s2t('channel'), s2t('mask') );
ref2.putIdentifier(s2t( 'layer' ), 2)
desc.putReference( s2t('null'), ref2 )
executeAction( s2t( "delete" ), desc, DialogModes.NO )

 

 

It would be very nice if someone found a way to work with the contents of a layer without activating it.

Translate
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 ,
Apr 02, 2020 Apr 02, 2020

DmitryEgorov, you are stating it's not possible and I just trust you.
In my understanding, it should be possible to point to which element the script should look at through ActionReference.
Anyway, thanks

Translate
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
Mentor ,
Apr 03, 2020 Apr 03, 2020

I am not saying that this is impossible 🙂 but I am saying that I do not know (and have not met) a working solution to such a situation.

In my understanding, the general principle of working with layers is this: to work with attributes you do not need to make it active, to work with content, you need to make it active.

Since the time required to select a layer is quite small, JJMack gave an excellent solution - remember which layer is selected, make the desired layer active, perform all necessary actions, restore the selection of the active layer.

Translate
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 ,
Apr 03, 2020 Apr 03, 2020

The key point for me is performance, because this is part of a script to scan the whole document and perform lots of optimizations without activating any layer, and changing the layer mask is the only task I was not able to complete without activating the layer.
If it's not possible, no worries, I don't see any problems activating the layer.

The JJMack's suggestion is interesting but I don't care about lose any pre-existing selection.

Translate
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 ,
Apr 03, 2020 Apr 03, 2020

If there is a existing selection you will lose it  if you set a an new selection by loading a channel.  If you do not want to loose a existing selection when the script is  run the first thing the script would need to do is to check to see if there is an active selection perhaps a try catch to see if there is an active selection bounds.  If there is save the active selection as a alpha channel  then do the scripts  normal processing and  before the script terminate check if  to see if you saved an active selection and if you did load the alpha channel as a selection and delete the alpha channel.

JJMack
Translate
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
LEGEND ,
Apr 03, 2020 Apr 03, 2020

Better than try...catch statement for checking selection bounds is:

sTT = stringIDToTypeID; (ref = new ActionReference()).putProperty(sTT('property'), sel = sTT('selection'))
ref.putEnumerated(sTT('document'), sTT('ordinal'), sTT('targetEnum')), executeActionGet(ref).hasKey(sel)
Translate
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 ,
Apr 03, 2020 Apr 03, 2020
LATEST

When I said "I don't care about lose any pre-existing selection" I was refering to selected layers, not selection itself. That was a miscommunication.
I should have used the word "activate" instead of "select".

Translate
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