Photoshop Script - Get name of visible Layer in Group/Layerset - javascript

i'm stuck with a script that detects which layer is visible in a (sub)layerset (aka Group) with the name "Color".
The script below checks for all visible layers and selects them. I can't get it working to do the same thing ONLY in the mentioned layerset.
Any help would be highly appreciated!
#target photoshop
app.bringToFront();
main();
function main(){
if(!documents.length) return;
var Vis = getVisLayers();
deselectLayers();
for(var a in Vis){
selectLayerById(Number(Vis[a]),true);
}
}
function getVisLayers(){
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
var count = executeActionGet(ref).getInteger(charIDToTypeID('NmbL')) +1;
var Names=[];
try{
activeDocument.backgroundLayer;
var i = 0; }catch(e){ var i = 1; };
for(i;i<count;i++){
if(i == 0) continue;
ref = new ActionReference();
ref.putIndex( charIDToTypeID( 'Lyr ' ), i );
var desc = executeActionGet(ref);
var layerName = desc.getString(charIDToTypeID( 'Nm ' ));
var Id = desc.getInteger(stringIDToTypeID( 'layerID' ));
if(layerName.match(/^<\/Layer group/) ) continue;
var layerType = typeIDToStringID(desc.getEnumerationValue( stringIDToTypeID( 'layerSection' )));
var isLayerSet =( layerType == 'layerSectionContent') ? false:true;
var vis = desc.getBoolean(charIDToTypeID( "Vsbl" ));
if(!isLayerSet && vis) Names.push(Id);
};
return Names;
};
function selectLayerById(ID, add) {
add = (add == undefined) ? add = false : add;
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID('Lyr '), ID);
var desc = new ActionDescriptor();
desc.putReference(charIDToTypeID('null'), ref);
if (add) {
desc.putEnumerated(stringIDToTypeID('selectionModifier'), stringIDToTypeID('selectionModifierType'), stringIDToTypeID('addToSelection'));
}
desc.putBoolean(charIDToTypeID('MkVs'), false);
executeAction(charIDToTypeID('slct'), desc, DialogModes.NO);
}
function deselectLayers() {
var desc01 = new ActionDescriptor();
var ref01 = new ActionReference();
ref01.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc01.putReference( charIDToTypeID('null'), ref01 );
executeAction( stringIDToTypeID('selectNoLayers'), desc01, DialogModes.NO );
};
enter image description here

Trouble with groups is that you have to jump at the deep end. Sadly the way Photoshop keeps track of it's layers isn't intuitive. The best thing to do is have a recursive function and look over ALL the layers - from that you'll be able to determine if it's a group or not. And then work out if it's visible.
var allLayers = new Array();
var theLayers = collectAllLayers(app.activeDocument, 0);
// function collect all layers
function collectAllLayers (theParent, level)
{
for (var m = theParent.layers.length - 1; m >= 0; m--)
{
var theLayer = theParent.layers[m];
if (theLayer.typename == "ArtLayer")
{
// find the art layers
if (theLayer.visible == true)
{
//do stuff here
}
}
else
{
allLayers.push(level + theLayer.name);
collectAllLayers(theLayer, level + 1)
}
}
}

Thanks to #Ghoul Fool i finally managed to get this working. I changed the code a bit as i only need to check which layer is visible and store this name as a variable. Would be great if someone more skilled could correct my code for others who will use it or parts of it.
Thanks again
// Checking which layer is visible in layeset (group) "Colors" in "Mockup.psd" aka mockupDoc and store it's name for later use in the "save" part.
var front = mockupDoc.layerSets.getByName("Front");
var colors = front.layerSets.getByName("Colors");
for (var m = colors.layers.length - 1; m >= 0; m--)
{
var theLayer = colors.layers[m];
if (theLayer.typename == "ArtLayer")
{
if (theLayer.visible == true)
{
// Sets a variable for the name of the visible Layer in the "Colors" Group, so i can use it later as a part of the Filename when saving.
var activeColor = theLayer.name;
}
}
};

Related

Photoshop script select all layers with same name as current layer

I need a photoshop script that selects all layers with the same name as the currently selected layer. The following code does the job:
if (app.documents.length > 0) {
activeDocument.suspendHistory('stuff', 'main()');
function main(){
if(!documents.length) return;
var myDoc = app.activeDocument;
var theName = myDoc.activeLayer.name;
var theResults = new Array;
selectAllLayers();
var selectedLayers = getSelectedLayersIdx();
for(var a = 0; a < selectedLayers.length; a++){
var thisName = layerName(Number(selectedLayers[a]));
if (thisName == theName) {
theResults.push(Number(selectedLayers[a]))
};
};
selectLayerByIndex(theResults[0], false);
for (var m = 1; m < theResults.length; m++) {
selectLayerByIndex(theResults[m], true);
};
}
};
function getSelectedLayersIdx(){
var selectedLayers = new Array;
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var desc = executeActionGet(ref);
if( desc.hasKey( stringIDToTypeID( 'targetLayers' ) ) ){
desc = desc.getList( stringIDToTypeID( 'targetLayers' ));
var c = desc.count
var selectedLayers = new Array();
for(var i=0;i<c;i++){
try{
activeDocument.backgroundLayer;
selectedLayers.push( desc.getReference( i ).getIndex() );
}catch(e){
selectedLayers.push( desc.getReference( i ).getIndex()+1 );
}
}
}else{
var ref = new ActionReference();
ref.putProperty( charIDToTypeID("Prpr") , charIDToTypeID( "ItmI" ));
ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
try{
activeDocument.backgroundLayer;
selectedLayers.push( executeActionGet(ref).getInteger(charIDToTypeID( "ItmI" ))-1);
}catch(e){
selectedLayers.push( executeActionGet(ref).getInteger(charIDToTypeID( "ItmI" )));
}
}
return selectedLayers;
};
function selectAllLayers() {
var desc29 = new ActionDescriptor();
var ref23 = new ActionReference();
ref23.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc29.putReference( charIDToTypeID('null'), ref23 );
executeAction( stringIDToTypeID('selectAllLayers'), desc29, DialogModes.NO );
};
function layerName(idx){
var ref = new ActionReference();
ref.putIndex( charIDToTypeID( "Lyr " ), idx);
var desc = executeActionGet(ref);
return desc.getString(stringIDToTypeID("name"));
};
function selectLayerByIndex(index,add){
add = undefined ? add = false:add
var ref = new ActionReference();
ref.putIndex(charIDToTypeID("Lyr "), index);
var desc = new ActionDescriptor();
desc.putReference(charIDToTypeID("null"), ref );
if(add) desc.putEnumerated( stringIDToTypeID( "selectionModifier" ), stringIDToTypeID( "selectionModifierType" ), stringIDToTypeID( "addToSelection" ) );
desc.putBoolean( charIDToTypeID( "MkVs" ), false );
try{
executeAction(charIDToTypeID("slct"), desc, DialogModes.NO );
}catch(e){
alert(e.message);
}
};
BUT, there is one problem, my files have a ton of layers and so it appears that this code must iterate through them all, as such each time i need to run this script it takes 7minutes to execute. Is there a way to optimize this such that it will be faster even in files with VERY HIGH layer counts? Thanks
Each Photoshop layer is given a unique ID - (generated at creation in numerical order - I think - don't quote me on that) So you can access each layer by the ID instead of layer.getByname. The code below will show you the ID of the currently selected layer. - The upshot being, if you know the ID, you can get by layerID. :)
To select more than one layer at a time: reuse the select_layer_by_ID with layer and true to add to the current selection.
Get layer by ID:
// Switch off any dialog boxes
displayDialogs = DialogModes.NO; // OFF
var srcDoc = app.activeDocument;
var theLayer = srcDoc.activeLayer;
var myLayerID = get_layer_id(theLayer);
srcDoc.activeLayer = srcDoc.layers[0]; //top layer
// now go back to original layer via layer ID!
// select by layer ID
select_layer_by_ID(myLayerID);
alert("Layer ID: " + myLayerID + "\n" + srcDoc.activeLayer.name);
// Switch off any dialog boxes
displayDialogs = DialogModes.ALL; // ON
// function SELECT LAYER BY ID(int, boolean)
// --------------------------------------------------------
function select_layer_by_ID(id, add)
{
if (add == undefined) add = false;
var desc1 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putIdentifier(charIDToTypeID('Lyr '), id);
desc1.putReference(charIDToTypeID('null'), ref1);
if (add) desc1.putEnumerated(stringIDToTypeID("selectionModifier"), stringIDToTypeID("selectionModifierType"), stringIDToTypeID("addToSelection"));
executeAction(charIDToTypeID('slct'), desc1, DialogModes.NO);
}
// function GET LAYER ID(obj)
// --------------------------------------------------------
function get_layer_id(alayer)
{
return alayer.id;
}

JS / JSX Script to generate unique PNGs from all permutations across all Photoshop Layer Groups and their Photoshop Layers

I'm looking into getting into generative art. My idea is to have Photoshop (CS5) generate a unique PNG for all permutations that exist while the script iterates through every LAYER across each LAYER GROUP (layerSets).
As an example, it would be similar to a character generator where:
PARENT layerSets consist of parts or locations across the face/body (A,B)
CHILD layers consist of accessories/styles (1,2,3)
Such that all generated PNG permutations would be: A1B1,A2B1,A3B1;A2B1,A2B2,A2B3;A3B1,A3B2,A3B3 only. (A1A2, A2A3, A1A3; B1B2, B2B3, B1B3 are not necessary; Standalone A1,A2,A3,B1,B2,B3 are not necessary).
I've found some code from #Mr.Online that generates random, and potentially redundant combinations from user-inputted quantity. His script requires that all layers be hidden by the user prior to running.
Thanks so much. Hopefully this'll help:
function Visible() {
var Grps = app.activeDocument.layerSets; // loops through all groups
for(var i = 0; i < Grps.length; i++){
var tmp = app.activeDocument.layerSets[i].layers.length;
app.activeDocument.layerSets[i].visible=true;
var groupChildArr = app.activeDocument.layerSets[i].layers;
var randLays = Math.floor(Math.random() * tmp);
groupChildArr[randLays].visible = true;
Save();
}
Revert();
}
function Save() {
var outFolder = app.activeDocument; // psd name
var outPath = outFolder.path;
var fName = "PNG"; // define folder name
var f = new Folder(outPath + "/" + fName);
if ( ! f.exists ) {
f.create()
}
var saveFile = new File(outPath + "/" + fName +"/" + "Pattern_" + num + ".png");
pngSaveOptions = new PNGSaveOptions();
pngSaveOptions.interlaced = false;
app.activeDocument.saveAs(saveFile, pngSaveOptions, true, Extension.LOWERCASE);
}
// Original code - revert function does not work
// for some users
//function Revert(){
// var idslct = charIDToTypeID( "slct" );
// var desc300 = new ActionDescriptor();
// var idnull = charIDToTypeID( "null" );
// var ref163 = new ActionReference();
// var idSnpS = charIDToTypeID( "SnpS" );
// ref163.putName( idSnpS, "test.psd" );
// desc300.putReference( idnull, ref163 );
// executeAction( idslct, desc300, DialogModes.NO );
//}
function Revert(){
var idRvrt = charIDToTypeID( "Rvrt" );
executeAction( idRvrt, undefined, DialogModes.NO );
}
var count = prompt("How many patterns you want","");
for (var x=0 ; x<count;x++){
var num = x+1;
Visible();
}
As you say, you need to ignore the random layers. However, if you know the number of layers & groups it's quite straight forward:
show_layers("A", "1");
show_layers("B", "1");
function show_layers(g, n)
{
// g is the name of the group (layerset)
// n is the name of the layer (artlayer)
srcDoc.activeLayer = srcDoc.layerSets.getByName(g).artLayers.getByName(n);
srcDoc.activeLayer.visible = true;
}
So, assuming all layers are switched off, you can get the layers by name and then make them visible.
Switching off all the layers is a bit more involved. You have to loop over all groups and then loop over its sublayers. Working with groups is a bit of a learning curve.
function switch_off_all_layers(bool)
{
var numLayers = app.activeDocument.layers.length;
// want to hide the background as well?
// default: background = visible
if (bool == undefined) bool = false;
if (bool == false)
{
numLayers -=1; // -1 for background
}
for(var i = 0 ; i < numLayers; i++)
{
if (app.activeDocument.layers[i].typename == "LayerSet")
{
app.activeDocument.layers[i].visible = true;
var subDoc = app.activeDocument.layers[i];
var numOfSubLayers = subDoc.layers.length;
for (var j = numOfSubLayers -1; j >= 0; j--)
{
var tempSubLayer = subDoc.layers[j];
tempSubLayer.visible = false;
}
}
}
}
Further to my explanation, if you can't supply the group layers & names then you fill want to loop over all groups and all layers.
var groupLayers = [];
var artLayers = [];
var theLayers = collectAllLayers(app.activeDocument, 0);
alert("Group layers\n" + groupLayers);
alert("Art layers\n" + artLayers);
// function collect all layers
function collectAllLayers (theParent, level)
{
for (var m = theParent.layers.length - 1; m >= 0; m--)
{
var theLayer = theParent.layers[m];
// apply the function to layersets;
if (theLayer.typename == "ArtLayer")
{
if (theLayer.isBackgroundLayer == true)
{
// add background layer (if needed)
// artLayers.push(theLayer.name);
}
else
{
// find the art layers
artLayers.push(theLayer.name);
}
}
else
{
// find the group layers
groupLayers.push(theLayer.name);
collectAllLayers(theLayer, level + 1)
}
}
}

Script to copy Layer Names to text box in Photoshop

I'm trying to create a script out of 2 working scripts
Goal:
We need a script that will go through all the layers in the current document, find each layer marked in certain color (Red for example), copy the names of only the layers marked in red, then put all names in a text layer one after another (attached example image).
Resources:
I found 2 scripts that each do half of what we need, so how to we put them together?
1) "Select by red" goes through the document and finds how many layers marked in "red" are in the document:
#target photoshop
if (app.documents.length > 0) {
// the file;
var myDocument = app.activeDocument;
// get number of layers;
var ref = new ActionReference();
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;
var theOthers = 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 not layer group collect values;
if (layerSet != "layerSectionEnd" /*&& layerSet != "layerSectionStart"*/ && isBackground != true) {
var theName = layerDesc.getString(stringIDToTypeID('name'));
var theID = layerDesc.getInteger(stringIDToTypeID('layerID'));
var visible = layerDesc.getBoolean(stringIDToTypeID("visible"));
var theColor = layerDesc.getEnumerationValue(stringIDToTypeID("color"));
if (typeIDToStringID(theColor) == "red") {theLayers.push([theName, theID])}
else {theOthers.push([theName, theID])}
};
}
catch (e) {};
};
// if layers are red;
if (theLayers.length > 0) {alert ("there are " + theLayers.length + " Red layers")}
else {alert ("no red layers")}
};
2) "Text box from layer name" takes the name of the currently selected layer, and pastes it into a new text layer called "Comp".
if (app.documents.length > 0) mainScript();
function mainScript() {
try{
var myLayerName = activeDocument.activeLayer.name;
var myLayerText = activeDocument.artLayers.add();
myLayerText.name = "Comp";
myLayerText.kind = LayerKind.TEXT;
var textProperty = myLayerText.textItem;
textProperty.size = 10;
textProperty.font = "Arial";
myLayerText.textItem.contents = myLayerName;
}catch (errStr){
alert(errStr);
}
}
Plan:
From my understanding, we need to start with a loop that's as long as our document size i.e. total number of layers for (var i = 0; i < doc.layers.length; i++).
Then layer by layer the script will check for color ID if (typeIDToStringID(theColor) == "red") . When it finds layer marked in red, it copies the layer name - then either stores it in array (to output later all at once), or creates a new text box and pastes the layer name myLayerText.textItem.contents = myLayerName.
Then for each time it finds another layer marked in red , it copies the layer name, and pastes it in the same text box just a line above/below previous layer name.
Any help is much appreciated!
The only thing you needed to do was to join the names of your theLayers array using the line-break symbol \r:
if (app.documents.length > 0)
{
// the file;
var myDocument = app.activeDocument;
// get number of layers;
var ref = new ActionReference();
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 not layer group collect values; if (layerSet != "layerSectionEnd" /*&& layerSet != "layerSectionStart"*/ && isBackground != true)
{
var theName = layerDesc.getString(stringIDToTypeID('name'));
var theColor = layerDesc.getEnumerationValue(stringIDToTypeID("color"));
if (typeIDToStringID(theColor) == "red")
{
theLayers.push(theName); // we only need names here
}
};
}
catch (e)
{};
};
// got our red layers in theLayers
var myLayerText = activeDocument.artLayers.add();
myLayerText.name = "Result";
myLayerText.kind = LayerKind.TEXT;
var textProperty = myLayerText.textItem;
textProperty.size = 10;
textProperty.font = "Arial";
myLayerText.textItem.contents = theLayers.join('\r'); // joining layers with a line-break: this is going to be textItem text
};
Here's the result:
I'd suggest you to take a course on JS on any learning website (code academy, etc): this won't take you more than an hour or two but you'll get the basic concepts: this will make your life much easier in terms of dealing with questions like this.

How to select a sublayer in Photoshop based on Javascript?

var docRef = app.activeDocument;
var layers = docRef.layers;
var myLayer = layers["组5"]; //this defines the layer that you want to get the selection from
var myLayer = app.activeDocument.layers["组5"];
//alert(myLayer.layers);
docRef.selection = null;//这句是让你没有选中任何图层
for (var i=0;i<myLayer.layers.length;i++){
if (myLayer.layers[i].name=="图层"){ // alert(myLayer.layers[i].name=="图层");
// alert(myLayer.layers[i].name);
myLayer.layers[i].selected=true;
}
}
I have code like this, when in photoshop cs , that some sublayers have names equal to "图层" , then this sublayer should be selected, but doesn't work, who knows how to get them selected?
To my knowledge this is not possible with DOM, but Action Manager code will do the job:
var myName = "Layer 5";
deselectLayers(); // deselecting all layers first
traverseAllLayers(myName);
function selectByID(id)
{
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID('Lyr '), id);
desc.putReference(charIDToTypeID('null'), ref);
desc.putEnumerated(stringIDToTypeID("selectionModifier"), stringIDToTypeID("selectionModifierType"), stringIDToTypeID("addToSelection"));
executeAction(charIDToTypeID('slct'), desc, DialogModes.NO);
};
function deselectLayers()
{
var desc60 = new ActionDescriptor();
var ref30 = new ActionReference();
ref30.putEnumerated(charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));
desc60.putReference(charIDToTypeID('null'), ref30);
executeAction(stringIDToTypeID('selectNoLayers'), desc60, DialogModes.NO);
};
function traverseAllLayers(n)
{
var ref0 = new ActionReference();
ref0.putProperty(charIDToTypeID('Prpr'), stringIDToTypeID('numberOfLayers'));
ref0.putEnumerated(charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
var desc0 = executeActionGet(ref0);
var i = desc0.getInteger(stringIDToTypeID('numberOfLayers'));
for (i; i > 0; i--)
{
ref = new ActionReference();
ref.putIndex(charIDToTypeID('Lyr '), i);
var desc = executeActionGet(ref);
var layerName = desc.getString(charIDToTypeID('Nm '));
var Id = desc.getInteger(stringIDToTypeID( 'layerID' ));
if (layerName == n) selectByID(Id) // selecting by ID, adding to selection
}
}

Photoshop Javascript List Layers

I want to list layers in json document. After my code :
#include json2.js
var doc = app.activeDocument;
var allLayers = [];
var allLayers = collectAllLayers(doc, allLayers);
function collectAllLayers (doc, allLayers){
for (var m = 0; m < doc.layers.length; m++){
var theLayer = doc.layers[m];
if (theLayer.typename === "ArtLayer"){
allLayers.push(theLayer);
}else{
collectAllLayers(theLayer, allLayers);
}
}
return allLayers;
}
var json = JSON.stringify(allLayers);
alert(json);
I am getting an error General Photoshop error occurred.This functionality may not be avaliable in this version of photoshop
I want to list groups and layers ex. like this :
Group1
> Layer 1
> Layer 2
> Group 2
> > Layer 3
> > Layer 4
> > Group 3
> > > Layer 5
> > > Layer 6
> Layer 3
Have you any ideas to do that?
Thanks for answers and help in advance!
I'd suggest you to read about Action Manager code, using DOM in Photoshop is mostly slow and limited. For example this non-recursive function will traverse through all layers and add layer DOM objects to your allLayers:
var doc = app.activeDocument;
var allLayers = [];
traverseLayersAMFlat(doc);
alert(allLayers);
//non-recursive action manager traversal function
function traverseLayersAMFlat(doc)
{
function _selectLayerById(ID) //select just this layer
{
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID('Lyr '), ID);
var desc = new ActionDescriptor();
desc.putReference(charIDToTypeID('null'), ref);
desc.putBoolean(charIDToTypeID('MkVs'), false);
executeAction(charIDToTypeID('slct'), desc, DialogModes.NO);
}//_selectLayerById
//how many layers are there in this document?
var ref = new ActionReference();
ref.putEnumerated(charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));
var count = executeActionGet(ref).getInteger(charIDToTypeID('NmbL'));
//traverse the list backwards (does parents first)
for (var i = count; i >= 1; i--)
{
ref = new ActionReference();
ref.putIndex(charIDToTypeID('Lyr '), i);
var desc = executeActionGet(ref); //access layer index #i
var layerID = desc.getInteger(stringIDToTypeID('layerID')); //ID for selecting by ID #
var layerSection = typeIDToStringID(desc.getEnumerationValue(stringIDToTypeID('layerSection'))); //layerSectionStart, layerSectionContent, laterSectionEnd
if (layerSection != 'layerSectionEnd')
{
_selectLayerById(layerID);
allLayers.push(app.activeDocument.activeLayer)
}
}//for i-- countdown
try
{ //if there is a magic background layer, process it, too
app.activeDocument.activeLayer = app.activeDocument.backgroundLayer;
allLayers.push(app.activeDocument.backgroundLayer)
} catch (e) {;}
}

Categories

Resources