Copy link to clipboard
Copied
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 );
}
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
JJMack, you are right. I was trying to combine both tasks in one script.
Thanks
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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)
Copy link to clipboard
Copied
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".
Find more inspiration, events, and resources on the new Adobe Community
Explore Now