OK, one more question
Currently I'm looping through all the layers getting their index like this:
Code: Select allfunction getLayerIds(pDoc, c) {
var ids = new Array();
for (var i = 0; i < c.artLayers.length; i++) {
ids[ids.length] = Stdlib.getLayerIndex(pDoc,c.artLayers)
}
for (var i = 0; i < c.layerSets.length; i++) {
ids.concat(getLayerIds(pDoc, c.layerSets));
}
return ids;
}
But it is dreadfully slow. And I've only got 4 layers in my test document - I suspect average for my users is going to be 20+. Any suggestions for speeding it up?
Thx
Anna
Getting PS's internal indexes for all layers
Getting PS's internal indexes for all layers
I am not sure how Stdlib is collecting the layer's index but the code below is the fastest that I have been able to come up with. Note that it needs CS3 or higher and that I have replace the charIDToTypeID calls for a little extra speed.
Code: Select allvar layersIndexeArray = collectIndexesAM();
alert( layersIndexeArray );
function collectIndexesAM(){
var allLayers = new Array();
var startLoop = Number( !hasBackground() );
var endLoop = getNumberOfLayer();
for( var l = startLoop;l < endLoop; l++){
while( !isValidActiveLayer( l ) ) {
l++;
}
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: Integer - 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() );
return res;
};
/*//////////////////////////////////////////////////////////////////////////////
// Function: isValidActiveLayer( )
// Description: Checks for 'real' layers
// Usage: if( isValidActiveLayer() )
// Input: None
// Return: Boolean - True if not the end of a Set
// Notes: Layersets have two indexes. One for start,
// one for end. This test that the layer in not
// a layerSelectionEnd.
//////////////////////////////////////////////////////////////////////////////*/
function isValidActiveLayer( idx ) {
var propName = stringIDToTypeID( 'layerSection' );// can't replace
var ref = new ActionReference();
ref.putProperty( 1349677170 , propName);
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: getNumberOfLayer
// Description: Gets gets the numberOfLayers property
// of the activeDocument
// Usage: var numLyrs= getNumberOfLayer();
// Input: None
// Return: Integer: Number of layers in document.
// Notes: Each layerset has two indexes. One for start
// and one for end.
// Dependices: CS3 or higher
//////////////////////////////////////////////////////////////////////////////*/
function getNumberOfLayer(){
var ref = new ActionReference();
ref.putEnumerated( 1147366766, 1332896878, 1416783732 );
var desc = executeActionGet(ref);
var numberOfLayer = desc.getInteger( 1315791436 );
return numberOfLayer;
};
Code: Select allvar layersIndexeArray = collectIndexesAM();
alert( layersIndexeArray );
function collectIndexesAM(){
var allLayers = new Array();
var startLoop = Number( !hasBackground() );
var endLoop = getNumberOfLayer();
for( var l = startLoop;l < endLoop; l++){
while( !isValidActiveLayer( l ) ) {
l++;
}
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: Integer - 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() );
return res;
};
/*//////////////////////////////////////////////////////////////////////////////
// Function: isValidActiveLayer( )
// Description: Checks for 'real' layers
// Usage: if( isValidActiveLayer() )
// Input: None
// Return: Boolean - True if not the end of a Set
// Notes: Layersets have two indexes. One for start,
// one for end. This test that the layer in not
// a layerSelectionEnd.
//////////////////////////////////////////////////////////////////////////////*/
function isValidActiveLayer( idx ) {
var propName = stringIDToTypeID( 'layerSection' );// can't replace
var ref = new ActionReference();
ref.putProperty( 1349677170 , propName);
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: getNumberOfLayer
// Description: Gets gets the numberOfLayers property
// of the activeDocument
// Usage: var numLyrs= getNumberOfLayer();
// Input: None
// Return: Integer: Number of layers in document.
// Notes: Each layerset has two indexes. One for start
// and one for end.
// Dependices: CS3 or higher
//////////////////////////////////////////////////////////////////////////////*/
function getNumberOfLayer(){
var ref = new ActionReference();
ref.putEnumerated( 1147366766, 1332896878, 1416783732 );
var desc = executeActionGet(ref);
var numberOfLayer = desc.getInteger( 1315791436 );
return numberOfLayer;
};
Getting PS's internal indexes for all layers
The problem with the Stdlib version is that you are working with Layer DOM objects. Mike's code gets around that by just accessing things below the DOM level.
Getting PS's internal indexes for all layers
It would appear I have bigger issues - this internal index is proving a poor way to get a hold of a specific layer repeatedly since the layer's index changes every time the user moves, deletes layers, etc. For some reason I thought this internal index was more static than that. Anyway, I suppose I could tag each layer with my own identifier as part of the layer name - but that relies on the user not changing it and I'd prefer if it was hidden from them altogether. Are there any other properties on the layer you can think of that might suit to store this in? (working with CS3+).
Getting PS's internal indexes for all layers
Yes the Action Manager layer index will change as the layers change. It also changes depending on if there is a background layer or not.
Layers also have a descriptor key named 'layerID'. That is an Integer that is unique to the layer. Both the index and ID of the background will be 0. But the ID for other layers/layersets will stay the same no matter where the layer is moved in the layer stack. If the layer is deleted, no other layers added later will have the same ID as the deleted layer.
However working with layers by ID is more limited than by index. Here are some functions that might be helpful.
Code: Select allfunction getLayerIdByIndex( idx) {
var ref = new ActionReference();
ref.putProperty( charIDToTypeID("Prpr") , stringIDToTypeID( "layerID" ));
ref.putIndex( charIDToTypeID("Lyr "), idx );
return executeActionGet(ref).getInteger( stringIDToTypeID( "layerID" ) );
}
function getLayerNameByLayerID(id) {
var ref = new ActionReference();
ref.putProperty( charIDToTypeID("Prpr") , charIDToTypeID( "Nm " ));
ref.putIdentifier( charIDToTypeID( "Lyr " ), id );
return executeActionGet(ref).getString(charIDToTypeID( "Nm " ));;
}
function makeActiveLayerByName( lyrname ){
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putName( charIDToTypeID( "Lyr " ), lyrname );
desc.putReference( charIDToTypeID( "null" ), ref );
desc.putBoolean( charIDToTypeID( "MkVs" ), false );
executeAction( charIDToTypeID( "slct" ), desc, DialogModes.NO );
}
Note that the makeActiveLayerByName function will make the top most layer with that name active regardless of layersets. But if the document has more than one layer with the same name there is no way in Action Manager to directly select the layer by name.
You can add a custom property to layer/layerset DOM object. But that requires making a reference to each layer/layerset for each layer/layerset you want to add the property and requires the DOM which is slow with docs that have a lot of layers
Layers also have a descriptor key named 'layerID'. That is an Integer that is unique to the layer. Both the index and ID of the background will be 0. But the ID for other layers/layersets will stay the same no matter where the layer is moved in the layer stack. If the layer is deleted, no other layers added later will have the same ID as the deleted layer.
However working with layers by ID is more limited than by index. Here are some functions that might be helpful.
Code: Select allfunction getLayerIdByIndex( idx) {
var ref = new ActionReference();
ref.putProperty( charIDToTypeID("Prpr") , stringIDToTypeID( "layerID" ));
ref.putIndex( charIDToTypeID("Lyr "), idx );
return executeActionGet(ref).getInteger( stringIDToTypeID( "layerID" ) );
}
function getLayerNameByLayerID(id) {
var ref = new ActionReference();
ref.putProperty( charIDToTypeID("Prpr") , charIDToTypeID( "Nm " ));
ref.putIdentifier( charIDToTypeID( "Lyr " ), id );
return executeActionGet(ref).getString(charIDToTypeID( "Nm " ));;
}
function makeActiveLayerByName( lyrname ){
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putName( charIDToTypeID( "Lyr " ), lyrname );
desc.putReference( charIDToTypeID( "null" ), ref );
desc.putBoolean( charIDToTypeID( "MkVs" ), false );
executeAction( charIDToTypeID( "slct" ), desc, DialogModes.NO );
}
Note that the makeActiveLayerByName function will make the top most layer with that name active regardless of layersets. But if the document has more than one layer with the same name there is no way in Action Manager to directly select the layer by name.
You can add a custom property to layer/layerset DOM object. But that requires making a reference to each layer/layerset for each layer/layerset you want to add the property and requires the DOM which is slow with docs that have a lot of layers
Getting PS's internal indexes for all layers
This sounds much more like what I was looking for - Thanks Mike.