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

PS script for toggling visibility of layers based on their names

Community Beginner ,
Nov 16, 2022 Nov 16, 2022

Copy link to clipboard

Copied

I work with Photoshop for a team that creates animated desktop pets. In a summary, when we work with asymmetrical characters, there are a lot of layers and groups that need to be turned on or off when we need to export the frames of the character looking to the other side. So there are layers that are called "Eye Asym", "Left Arm Asym", "Right Ear Asym", etc., and those can be inside of multiple groups that are inside of other groups.

I'm trying to set a script that can toggle on/off all groups or layers that contain " Asym" on the name, all at once.

After a lot of research, and multiple failed attempts, the only one I have found that is close to work is this one: https://community.adobe.com/t5/photoshop-ecosystem-discussions/script-request-for-toggling-visibilit... (General expression changed for my case)

#target photoshop

var re = /.* Asym/; // a reg exp

var matches = collectNamesAM(re); // get array of matching layer indexes

for( var l = 0; l < matches.length; l++ ){

  makeActiveByIndex( matches, false );

  // do something with layer

  var docLayer = app.activeDocument.activeLayer;

  docLayer.visible=docLayer.visible==false;

  // test matches with alert

  //alert(app.activeDocument.activeLayer.name);

} // next match if any

function collectNamesAM(re){

  var allLayers = new Array();

  var startLoop = Number( !hasBackground() );

  var endLoop = getNumberOfLayer();

  for( var l = startLoop;l < endLoop; l++){

  while( !isValidActiveLayer( l ) ) {

  l++;

  }

  if( getLayerNameByIndex( l ).match(re) != null){

  allLayers.push( l );

  }

  }

  return allLayers;

};

/*//////////////////////////////////////////////////////////////////////////////

// Function: getActiveLayerIndex

// Description: Gets gets the Action Manager API index

//                        of activeLayer corrected for Background Layer

// Usage: var idx = getActiveLayerIndex();

// Input: None

// Return: Number - correct AM itemIndex

// Dependices: hasBackground

//////////////////////////////////////////////////////////////////////////////*/

function getActiveLayerIndex() {

  var ref = new ActionReference();

  ref.putProperty( 1349677170 , 1232366921 );

  ref.putEnumerated( 1283027488, 1332896878, 1416783732 );

  var res = executeActionGet(ref).getInteger( 1232366921 )

  - Number( hasBackground() );

  res == 4 ? res++:res // why the skip in this doc?

  return res;

}

/*//////////////////////////////////////////////////////////////////////////////

// Function: isValidActiveLayer( )

// Description: Checks LayerSection for 'real' layers

// Usage: if( isValidActiveLayer() )

// Input: None

// Return: Boolean - True if not the end of a Set

// Notes:  Needed only if the layer was made active

//              using Action Manager API

//////////////////////////////////////////////////////////////////////////////*/

function isValidActiveLayer( idx ) {

  var propName = stringIDToTypeID( 'layerSection' ); // can't replace

  var ref = new ActionReference();

  ref.putProperty( 1349677170 , propName); // TypeID for "Prpr"

  // 'Lyr ", idx

  ref.putIndex( 1283027488, idx );

  var desc =  executeActionGet( ref );

  var type = desc.getEnumerationValue( propName );

  var res = typeIDToStringID( type );

  return res == 'layerSectionEnd' ? false:true;

};

/*//////////////////////////////////////////////////////////////////////////////

// Function: hasBackground

// Description: Test for background layer using AM API

// Usage: if( hasBackground() );

// Input: None

// Return: Boolean - true if doc has background layer

// Notes:  Requires the document to be active

//  DOM:  App.Document.backgroundLayer

//////////////////////////////////////////////////////////////////////////////*/

function hasBackground(){

  var res = undefined;

  try{

  var ref = new ActionReference();

  ref.putProperty( 1349677170 , 1315774496);

  ref.putIndex( 1283027488, 0 );

  executeActionGet(ref).getString(1315774496 );;

  res = true;

  }catch(e){ res = false}

  return res;

};

function makeActiveByIndex( idx, forceVisible ){

  try{

  var desc = new ActionDescriptor();

  var ref = new ActionReference();

  ref.putIndex(charIDToTypeID( "Lyr " ), idx)

  desc.putReference( charIDToTypeID( "null" ), ref );

  desc.putBoolean( charIDToTypeID( "MkVs" ), forceVisible );

  executeAction( charIDToTypeID( "slct" ), desc, DialogModes.NO );

  }catch(e){ return -1;}

};

function getNumberOfLayer(){

  var ref = new ActionReference();

  ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );

  var desc = executeActionGet(ref);

  var numberOfLayer = desc.getInteger(charIDToTypeID("NmbL"));

  return numberOfLayer;

};

function getLayerNameByIndex( idx ) {

  var ref = new ActionReference();

  ref.putProperty( charIDToTypeID("Prpr") , charIDToTypeID( "Nm  " ));

  ref.putIndex( charIDToTypeID( "Lyr " ), idx );

  return executeActionGet(ref).getString(charIDToTypeID( "Nm  " ));;

};

But it doesn't work properly, because it toggles multiple times in a row the top group of layers that contains a layer with the word " Asym" inside, instead of toggling those layers once.

I appreciate any help you can provide.

TOPICS
Actions and scripting

Views

1.3K

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 , Nov 18, 2022 Nov 18, 2022

That Script referred to a specific name, so here is one with a few changes: 

// hide or show layers with a certain name-part;
// 2022, use it at your own risk;
if (app.documents.length > 0) {
    var thisName = "Asym";
    var theLayers = collectLayersByName(thisName);
    for (var x = 0; x < theLayers.length; x++) {
        if (theLayers[x][3] == true) {var idhide = stringIDToTypeID( "hide" )}
        else {var idhide = stringIDToTypeID( "show" )};
        var desc22 = new ActionDescriptor();
 
...

Votes

Translate

Translate
Adobe
Community Expert ,
Nov 18, 2022 Nov 18, 2022

Copy link to clipboard

Copied

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 Beginner ,
Nov 18, 2022 Nov 18, 2022

Copy link to clipboard

Copied

OMG yes! why didn't I find this one during all the research I made!?

It works with predefined names. Is there a way to make it works with Reg Ex? or at least to work with names that contain a specific word within?

Because all the names of the layers I need to toggle are different, but they all share the same word "Asym"

Ie. "Left Ear Asym", "Right Arm Asym", "Left Eye Asym", etc.

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 ,
Nov 18, 2022 Nov 18, 2022

Copy link to clipboard

Copied

I posted an edited version after the initial post, did you check that out? 

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 ,
Nov 18, 2022 Nov 18, 2022

Copy link to clipboard

Copied

That Script referred to a specific name, so here is one with a few changes: 

// hide or show layers with a certain name-part;
// 2022, use it at your own risk;
if (app.documents.length > 0) {
    var thisName = "Asym";
    var theLayers = collectLayersByName(thisName);
    for (var x = 0; x < theLayers.length; x++) {
        if (theLayers[x][3] == true) {var idhide = stringIDToTypeID( "hide" )}
        else {var idhide = stringIDToTypeID( "show" )};
        var desc22 = new ActionDescriptor();
        var list2 = new ActionList();
        var ref8 = new ActionReference();
        ref8.putIdentifier( stringIDToTypeID( "layer" ), theLayers[x][2] );
        list2.putReference( ref8 );
        desc22.putList( stringIDToTypeID( "null" ), list2 );
        executeAction( idhide, desc22, DialogModes.NO );
        }
    };
////// collect layers with certain name //////
function collectLayersByName (aName) {
    // get number of layers;
    var ref = new ActionReference();
    ref.putProperty(stringIDToTypeID('property'), stringIDToTypeID('numberOfLayers'));
    ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); 
    var applicationDesc = executeActionGet(ref);
    var theNumber = applicationDesc.getInteger(stringIDToTypeID("numberOfLayers"));
    // process the layers;
    var theLayers = new Array;
    for (var m = 0; m <= theNumber; 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"));
    // if group collect values;
    if (layerSet != "layerSectionEnd" /*&& layerSet != "layerSectionStart"*/ && isBackground != true) {
    var theName = layerDesc.getString(stringIDToTypeID('name'));
    var theID = layerDesc.getInteger(stringIDToTypeID('layerID'));
    var theIndex = layerDesc.getInteger(stringIDToTypeID('itemIndex'));
    var theVisibility = layerDesc.getBoolean(stringIDToTypeID('visible'));
    if (theName.match(aName) != null) {theLayers.push([theName, theIndex, theID, theVisibility])}
    };
    }
    catch (e) {};
    };
    return theLayers
    };

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 Beginner ,
Nov 18, 2022 Nov 18, 2022

Copy link to clipboard

Copied

LATEST

It works perfectly!

Thank you very much for your 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