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

Script request for toggling visibility of multiple layers using regex

Community Beginner ,
Jul 14, 2015 Jul 14, 2015

Hello,

I have done a ton of search, trail / error, and finally need to reach out for assistance.

I am attempting to create a PS script that toggles visibility of layers AND groups based on a regular expression in a PS document.

EXAMPLE STRUCTURE OF PS GROUPS & LAYERS

=======================================

• // example

• header

     - some-layer

     - // test

• footer

     - another-layer

     - // content-area

Bullet = Group

Hyphen = Layer


This script should hide both "// example", "// test", and "// content-area" on run. Running the script again would ideally reveal these layer(s) and group(s).


I have managed to located two scripts that do each half of the desired outcome below.

Part 1: Use Regular expression to locate each layer and group (I have modified the reg exp to use case):

Re: Script to search layer names

by: Michael L Hale

var re = /\/\/\ .*/; // 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

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

};

This script shows an alert for each layer / group name that matches - It is locating the layers / groups!

Now I need these layers / groups to simultaneously hide or appear depending on their status.


I located a script that toggles visibility for a specific name (in this case 'GRID') here:

photoshop-grid-toggle/Toggle Grid.jsx at master · squarefrog/photoshop-grid-toggle · GitHub

var gridName = "GRID"; // Change to whatever you call your grid layer set.

function toggleGridLayer() {

    if (app.documents.length > 0) {

        var gridLayer = app.activeDocument.layerSets.getByName(gridName);

        gridLayer.visible = !gridLayer.visible;

    }

}

toggleGridLayer();

Essentially, I would like to fuse the toggling visibility script into the regular expression script. Any and all help would be awesome. Thanks in advance!


Note: Using PS CC 2015

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

correct answers 1 Correct answer

Community Expert , Jul 14, 2015 Jul 14, 2015

That script is all on one line and is difficult to see where separate lines are. If you want code to turn on or off a layer you can use:

var docLayer = app.activeDocument.activeLayer;

docLayer.visible=docLayer.visible==false;

Translate
Adobe
Community Expert ,
Jul 14, 2015 Jul 14, 2015

That script is all on one line and is difficult to see where separate lines are. If you want code to turn on or off a layer you can use:

var docLayer = app.activeDocument.activeLayer;

docLayer.visible=docLayer.visible==false;

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 Beginner ,
Jul 14, 2015 Jul 14, 2015

Your solution worked! I added the two lines you provided into the script at line 6 & 7 (after "// do something with layer") and it its toggling the visibility perfectly. The only thing to note for others that may come across this, is that the script does not find a match on the top most layer / group of the stack. The elements that I am toggling are nested, so this is not a concern for me. Just making a note.

P.S. - Sorry about not inserting the JS into the code formatting as pasting would wrap after I posted. It looked fine while editing in the reply field. Hm.


var re = /\/\/\ .*/; // 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  " ));;

};

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 ,
Jul 14, 2015 Jul 14, 2015

Glad it's working for you!

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 ,
Jul 15, 2015 Jul 15, 2015

Hi Chuck Uebele,

since a long time I missed the possibility to mark an answer as helpful. How did you mark my answer as helpful?

Best regards

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 ,
Jul 15, 2015 Jul 15, 2015

pixxxel schubser I'm a mod, so I can mark answers as helpful. It's been removed for regular users for some odd reason.

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 ,
Jul 15, 2015 Jul 15, 2015
LATEST

What a shame. I guessed it.

But thank you for your answer.

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
Enthusiast ,
Jul 14, 2015 Jul 14, 2015

Hope it helps, MSpangenberg.

I have no CC2015 to test. Only CC2014

// string for regexp verification

var myRegexp = "example_test_content-area";

//

var wasHere = app.activeDocument.activeLayer;

var onOff = false;

// The group "example" visibility will dictate the other artlayers visibility

for (var a=0; a<app.activeDocument.layers.length ; a++) {

    //

    if (myRegexp.match(new RegExp(app.activeDocument.layers.name)) != null) {

        app.activeDocument.layers.visible = (String(app.activeDocument.layers.visible) == 'true') ? false : true;

        onOff = app.activeDocument.layers.visible;

    } else {

        // to activate a artlayer or group, will also put its visibility on at the same time (important):

        app.activeDocument.activeLayer = app.activeDocument.layers;

        for (var b=0; b<app.activeDocument.layers.artLayers.length ; b++) {

            if (myRegexp.match(new RegExp(app.activeDocument.layers.artLayers.name)) != null) {

                app.activeDocument.layers.artLayers.visible = onOff;

            }

        }

    }

}

// go back to the initial active layer

app.activeDocument.activeLayer = wasHere;

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 Beginner ,
Jul 14, 2015 Jul 14, 2015

Thanks for the reply!

I added my regular expression into the variable:

var myRegexp = /\/\/\ .*/;

Running the script, I receive the following error:

Error 24: myRegexp.match is not a function.

Line: 9

->      if (myRegexp.match(new RegExp(app.activeDocument.layers.name)) != null) {

Any ideas?

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 ,
Jul 14, 2015 Jul 14, 2015

Hi MSpangenberg‌,

you should use something like this (standalone "three-liner") in your script:

if (app.activeDocument.activeLayer.name.match(/\/\/\ .*/) != null) {

    alert("found: " + app.activeDocument.activeLayer.name.match(/\/\/\ .*/));

    }

Have fun

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