Copy link to clipboard
Copied
Hi all; I am new to coding in general and of course Photoshop scripting.
I am wondering how I could select the top-most (or in my case specifically, the second-to-top most) layer in a stack of clipping masks. Refer to the picture below; say I am currently on Layer 4.
When I run the script, it needs to jump to Layer 6, and add a new layer. Note that this stack could be much bigger, but will never be smaller than 2. (And also instead of being on Layer 4, I might be on Layer 1 (the base layer of the stack).)
Of course it might also be in a group, and that group might be in a group, etc, and that there are also multiple clipping masks in the document.
I have a script that goes to the base layer of the stack, but unfortunately I don't know how to go the other way, and this script only works with the first stack that appears in the document.
Any guidance to set me in the right direction would be helpful!
Try this:
#target photoshop
s2t = stringIDToTypeID;
var idx = getTagetLayerIndex() + (isGrouped() ? 0 : 1);
if (isGrouped(idx)) {
while (isGrouped(++idx)) { }
selectLayerByIndex(idx - 2)
addLayer(true)
}
function isGrouped(index) {
(r = new ActionReference()).putProperty(s2t('property'), p = s2t('group'));
index != undefined ? r.putIndex(s2t('layer'), index)
: r.putEnumerated(s2t('layer'), s2t('ordinal'), s2t('targetEnum'));
try { return executeActionGet(r).get
...
Copy link to clipboard
Copied
Are you trying to access all clipped layers in the file, or do you manually select the group of clipped layers. As far as I know, you need to make a loop to go through the clipped layers, until you find one that isn't clipped, then go back in the loop.
Copy link to clipboard
Copied
I'm not sure what the question you're asking is exactly, but I only want to have the script occur on the clipping stack I have currently selected. For example, it would go like this:
I manually select a layer (Layer 3 for example) that is in a stack of clipping masks layers (which would include only Layer 1, 3, 4, 5, 6 and 2; no others), activate the script, and it would send me to the second top most layer in the stack, so Layer 6. Or, incidentally, if I am already on Layer 6, it would just keep me there.
you need to make a loop to go through the clipped layers, until you find one that isn't clipped, then go back in the loop.
Do you mean it loops through every clipped layer in the entire document, or just the ones that are apart of the stack of the layer I currently have selected? Iterating through the entire document would be very inefficient for large documents, so I hope that is not the case.
Copy link to clipboard
Copied
I think I found something that works, partial code credit goes to Sergey Kritskiy:
var doc = activeDocument;
if (!doc.activeLayer.grouped) // If base layer is selected, move into the clipping stack
{
selectLayer('Frwr');
}
while (doc.activeLayer.grouped)
{
selectLayer('Frwr');
};
// Move two layers down
selectLayer('Bckw');
selectLayer('Bckw');
function selectLayer(input)
{
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated(cTID('Lyr '), cTID('Ordn'), cTID(input));
desc.putReference(cTID('null'), ref);
desc.putBoolean(cTID('MkVs'), false);
executeAction(cTID('slct'), desc, DialogModes.NO);
};
function cTID(s)
{
return app.charIDToTypeID(s);
};
This is the basic version, but I have also expanded upon it to more suit my needs:
var doc = activeDocument;
if (!doc.activeLayer.grouped) // If base layer is selected, move into the clipping stack
{
selectLayer('Frwr');
}
if (doc.activeLayer.grouped)
{
while (doc.activeLayer.grouped)
{
selectLayer('Frwr');
};
// Move two layers down
selectLayer('Bckw');
selectLayer('Bckw');
addLayer();
}
else
{
// if the layer above the current layer is not a clipped layer
// do nothing
};
function selectLayer(input)
{
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated(cTID('Lyr '), cTID('Ordn'), cTID(input));
desc.putReference(cTID('null'), ref);
desc.putBoolean(cTID('MkVs'), false);
executeAction(cTID('slct'), desc, DialogModes.NO);
};
function addLayer()
{
var idMk = charIDToTypeID( "Mk " );
var desc22 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref9 = new ActionReference();
var idLyr = charIDToTypeID( "Lyr " );
ref9.putClass( idLyr );
desc22.putReference( idnull, ref9 );
var idUsng = charIDToTypeID( "Usng" );
var desc23 = new ActionDescriptor();
var idGrup = charIDToTypeID( "Grup" );
desc23.putBoolean( idGrup, true );
var idLyr = charIDToTypeID( "Lyr " );
desc22.putObject( idUsng, idLyr, desc23 );
var idLyrI = charIDToTypeID( "LyrI" );
desc22.putInteger( idLyrI, 903 );
executeAction( idMk, desc22, DialogModes.NO );
}
function cTID(s)
{
return app.charIDToTypeID(s);
};
This is greatly inefficient as the larger the clipping stack is, the more time it will take to execute the script; any ideas on making this go faster is much appreciated!
Copy link to clipboard
Copied
Try this:
#target photoshop
s2t = stringIDToTypeID;
var idx = getTagetLayerIndex() + (isGrouped() ? 0 : 1);
if (isGrouped(idx)) {
while (isGrouped(++idx)) { }
selectLayerByIndex(idx - 2)
addLayer(true)
}
function isGrouped(index) {
(r = new ActionReference()).putProperty(s2t('property'), p = s2t('group'));
index != undefined ? r.putIndex(s2t('layer'), index)
: r.putEnumerated(s2t('layer'), s2t('ordinal'), s2t('targetEnum'));
try { return executeActionGet(r).getBoolean(p) } catch (e) { return null }
}
function getTagetLayerIndex() {
(r = new ActionReference()).putProperty(s2t('property'), p = s2t('itemIndex'));
r.putEnumerated(s2t('layer'), s2t('ordinal'), s2t('targetEnum'));
var idx = executeActionGet(r).getInteger(p);
(r = new ActionReference()).putProperty(s2t('property'), p = s2t('hasBackgroundLayer'));
r.putEnumerated(s2t('document'), s2t('ordinal'), s2t('targetEnum'));
return idx - (executeActionGet(r).getBoolean(p) ? 1 : 0);
}
function selectLayerByIndex(index) {
(r = new ActionReference()).putIndex(s2t('layer'), index);
(d = new ActionDescriptor()).putReference(s2t('null'), r);
executeAction(s2t('select'), d, DialogModes.NO)
}
function addLayer(group) {
group = group == undefined ? false : true;
(r = new ActionReference()).putClass(s2t('layer'));
(d = new ActionDescriptor()).putReference(s2t('null'), r);
(d1 = new ActionDescriptor()).putBoolean(s2t('group'), group);
d.putObject(s2t('using'), s2t('layer'), d1);
executeAction(s2t('make'), d, DialogModes.NO);
}
Copy link to clipboard
Copied
That's incredible! I'm not sure how you managed to make it go so much faster. I appreciate the code write up - it seems like mumbo jumbo code magic to me haha.
Copy link to clipboard
Copied
He's supposed to be future ACP - that explains his powerful abbilities 😄
Copy link to clipboard
Copied
Looks like you have a script along the lines that I was mentioning: looping up until a grouped layer isn't encountered. I'm not sure about how to make it faster, as I don't know of any way to determine what layer is at the top of the stake without looping through them.
I had asked if you manually select the clipped layer sets to select the one you want to find the top clipped layer. You still have to loop through that set, but not the entire document, which would take a long time.