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

Go to the top-most layer in a set of clipping masked-layers

Explorer ,
Aug 04, 2021 Aug 04, 2021

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.

default84n0jwqtkgky_1-1628119948223.png

 

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!

TOPICS
Actions and scripting , Windows

Views

375

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

Guide , Aug 04, 2021 Aug 04, 2021

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
...

Votes

Translate

Translate
Adobe
Community Expert ,
Aug 04, 2021 Aug 04, 2021

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.

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 ,
Aug 04, 2021 Aug 04, 2021

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.

quote

 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.

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 ,
Aug 04, 2021 Aug 04, 2021

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!

 

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
Guide ,
Aug 04, 2021 Aug 04, 2021

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

 

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 ,
Aug 05, 2021 Aug 05, 2021

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.

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
LEGEND ,
Aug 05, 2021 Aug 05, 2021

Copy link to clipboard

Copied

LATEST

He's supposed to be future ACP - that explains his powerful abbilities 😄

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 ,
Aug 04, 2021 Aug 04, 2021

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.

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