get index without activating layer?

Anyone, especially newbies, asking for help with Photoshop Scripting and Photoshop Automation - as opposed to those contributing to discussion about an aspect of Photoshop Scripting

Moderators: Tom, Kukurykus

pfaffenbichler

get index without activating layer?

Post by pfaffenbichler »

Collecting an Array of Layers (via DOM) usually takes significantly longer than an Array of the Layers’s indices and IDs (via AM) in my tests.
Code: Select all// 2014, use it at your own risk;
#target "photoshop-70.032"
if (app.documents.length > 0) {
var myDocument = app.activeDocument;
//
var time1 = Number(timeString());
//
main ();
//
var time2 = Number(timeString());
//
var time3 = Number(timeString());
//
LayersArray = []
RecorreLayers(myDocument);
//
var time4 = Number(timeString());
//
alert("am: "+((time2-time1)/1000)+" seconds\nstart "+time1+"\nend "+time2+"\n\ndom: "+((time4-time3)/1000)+" seconds\nstart "+time3+"\nend "+time4);
};
////////////////////////////////////
function main () {
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var applicationDesc = executeActionGet(ref);
var theNumber = applicationDesc.getInteger(stringIDToTypeID("numberOfLayers"));
// anumber is intended to keep track of layerset depth;
var aNumber = 0;
var theArray = new Array;
var theGroups = new Array;
////// work through layers //////
for (var m = theNumber; m >= 0; 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"));
var theName = layerDesc.getString(stringIDToTypeID('name'));
var theID = layerDesc.getInteger(stringIDToTypeID('layerID'));
////////////////////////////////////
// if group start:
if (layerSet == "layerSectionStart" && isBackground != true) {
if (aNumber == 0) {var setArray = [[theName, m]]}
else {
// include groups in array;
   var thisArray = [[theName, m, theID]];
   for (var o = setArray.length - 1; o >= 0; o--) {thisArray.push(setArray[o])};
   theArray.push(thisArray)
// set array;
   setArray.push([theName, m, theID])
   };
theGroups.push([theName, m, theID]);
// add to mark group;
aNumber++
};
// if group end;
if (layerSet == "layerSectionEnd" && isBackground != true) {
// subtract to mark end of group;
aNumber--;
if (aNumber == 0) {var setArray = []}
else {setArray.pop()}
};
// if neither group start or end;
if (layerSet != "layerSectionEnd" && layerSet != "layerSectionStart" /*&& isBackground != true*/) {
// if anumber is 0 layer is top level;
if (aNumber == 0) {theArray.push([[theName, m, theID, "document"]])}
else {
   var thisArray = [[theName, m, theID]];
   for (var o = setArray.length - 1; o >= 0; o--) {thisArray.push(setArray[o])};
   theArray.push(thisArray)
   };
};
////////////////////////////////////
}
catch (e) {};
};
// the results;
//alert ("the layers are situated in:"+"\n"+theArray.join("\n"));
};
////// function to get the date //////
function timeString () {
   var now = new Date();
   return now.getTime()
   };
// http://ps-scripts.com/bb/viewtopic.php?f=9&t=5921
// colect array of layers from dom;
function RecorreLayers(ref) {
    // declare local variables
    var len = ref.layers.length;
    //layers bottom to top
        for (var i = len - 1; i >= 0; i--) {
            Recorre();
        }

    function Recorre() {
        var layer = ref.layers;

        // check for groups
        if (layer.typename == 'LayerSet') {
            RecorreLayers(layer);
            LayersArray.push(layer)
        }
        // rename layer
        else {
            LayersArray.push(layer)
        }
    }
}
buga

get index without activating layer?

Post by buga »

I thought that combining the two codes could have what I want.

An array of indices and an array of layers as variables, where the index of each layer is its corresponding counter array.

I guess it takes more time, but I can think of many uses.

One last question. Is it possible to create a loader that appears while functions are executed?

I say this because in files with many layers, the processing of information could be time consuming. If I could show a charger would be great. Is this possible? maybe in a script or panel.

Thank you very much for your help.

regards
pfaffenbichler

get index without activating layer?

Post by pfaffenbichler »

An array of indices and an array of layers as variables, where the index of each layer is its corresponding counter array.
Why do you even need an Array of the Layers?
An Array of the indices and/or (if necessary) layerIDs should work just fine.
buga

get index without activating layer?

Post by buga »

Forgive my ignorance, I am new to programming.

I do not usually work with ID.

why that would be used in a script?

I have another question with your code.

How can check the empty groups? Could you help me?

Thank you so much for your time
pfaffenbichler

get index without activating layer?

Post by pfaffenbichler »

This is an amended version of some of your previous code.
The randomly chosen Layer is selected via its layerID (after an alert of its name so you can verify it’s the correct one).
But instead of selecting the Layer one could also duplicate it for example.
Code: Select all// 2014, use it at your own risk;
#target "photoshop-70.032"
function randomIntFromInterval(min,max){
    return Math.floor(Math.random()*(max-min+1)+min);
};
function GetIndexWithoutActive(layer) {   
    alert("I would like to get the index of: \n\n"+layer)   
};
////////////////////////////////////
var LayersArray = getLayersIncexAndID();
randomElement= randomIntFromInterval(0,LayersArray.length-1);
layer = LayersArray[randomElement][0];
alert (layer[0]);
selectLayerByID(layer[2], false);
////////////////////////////////////
function getLayersIncexAndID () {
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var applicationDesc = executeActionGet(ref);
var theNumber = applicationDesc.getInteger(stringIDToTypeID("numberOfLayers"));
// anumber is intended to keep track of layerset depth;
var aNumber = 0;
var theArray = new Array;
var theGroups = new Array;
////// work through layers //////
for (var m = theNumber; m >= 0; 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"));
var theName = layerDesc.getString(stringIDToTypeID('name'));
var theID = layerDesc.getInteger(stringIDToTypeID('layerID'));
////////////////////////////////////
// if group start:
if (layerSet == "layerSectionStart" && isBackground != true) {
if (aNumber == 0) {var setArray = [[theName, m]]}
else {
// include groups in array;
   var thisArray = [[theName, m, theID]];
   for (var o = setArray.length - 1; o >= 0; o--) {thisArray.push(setArray[o])};
   theArray.push(thisArray)
// set array;
   setArray.push([theName, m, theID])
   };
theGroups.push([theName, m, theID]);
// add to mark group;
aNumber++
};
// if group end;
if (layerSet == "layerSectionEnd" && isBackground != true) {
// subtract to mark end of group;
aNumber--;
if (aNumber == 0) {var setArray = []}
else {setArray.pop()}
};
// if neither group start or end;
if (layerSet != "layerSectionEnd" && layerSet != "layerSectionStart" /*&& isBackground != true*/) {
// if anumber is 0 layer is top level;
if (aNumber == 0) {theArray.push([[theName, m, theID, "document"]])}
else {
   var thisArray = [[theName, m, theID]];
   for (var o = setArray.length - 1; o >= 0; o--) {thisArray.push(setArray[o])};
   theArray.push(thisArray)
   };
};
////////////////////////////////////
}
catch (e) {};
};
// the results;
return theArray
alert ("the layers are situated in:"+"\n"+theArray.join("\n"));
};
// by mike hale, via paul riggott;
// http://forums.adobe.com/message/1944754#1944754
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);
}
};
////// based on paul riggott’s code //////
function selectLayerByID(index,add){
add = undefined ? add = false:add
var ref = new ActionReference();
    ref.putIdentifier(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);
}
};
buga

get index without activating layer?

Post by buga »

The ID is unique?

That is, if we remove layers indexes change.

Suppose I want to re-select the layers that had originally selected, but some have been removed.
It could do so by the ID? and these also change as indexes?

To check the empty groups. I found this script that removes the empty layers in layercomps and has a charger

Code: Select all/**
 * Photoshop layer comp cleanup script
 *
 * This script will run through all the layer comps, find layers that are hidden in every comp
 * as well as any groups that are empty and delete them. Save before doing this just in case ;)
 *
 * @author Glen Cheney (http://glencheney)
 * @version 1.1
 * @date 7.10.12
 */
 
 
// Enable double clicking from the
// Macintosh Finder or the Windows Explorer
#target photoshop
 
// Make Photoshop the frontmost application
app.bringToFront();
 
var doc = app.activeDocument;
 
"use strict";
 
var Cleanup = function() {
    this.totals = {};
    this.results = {
        layersRemoved: 0,
        groupsRemoved: 0
    }
 
    // Do it!
    this.run();
};
 
Cleanup.prototype.run = function() {
    // Confirm running the script
    if (!confirm("Are you sure you want to delete unused layers and groups in layer comps?")) {
        return;
    }
 
    // Index layers and groups
    this.totals = this.calculateTotals();
 
    // Delete unused layers
    this.findObsoleteLayers();
 
    // Delete unused groups
    this.deleteEmptyGroups();
 
    // Display a summary
    this.summary();
};
 
// Counts the total layers in the document
// Creates an array of groups
Cleanup.prototype.calculateTotals = function() {
    var layerCount = 0,
        groups = [],
        layers = [],
        loop = function(group) {
            var i = 0,
                j = 0;
            if (!group) {
                group = doc;
            }
 
            // Show some progress!?
            progress.updateText('Current group: ' + group.name);
 
            // If this group has groups, run this function again
            if (group.layerSets.length > 0) {
                for (; i < group.layerSets.length; i++) {
                    loop(group.layerSets);
                }
            }
 
            // Add the art layers to our layers array
            for (; j < group.artLayers.length; j++ ) {
                layers.push(group.artLayers[j]);
            }
 
            groups.push(group);
            layerCount += group.artLayers.length;
        },
        progress = new Progress({
            title: 'This may take several minutes...',
            message: 'Retrieving layers and groups'
        });
 
 
    loop();
    progress.close();
 
    return {
        layers: layers,
        numLayers: layerCount,
        groups: groups,
        numGroups: groups.length
    };
};
 
// Loops through the document and removes empty groups
Cleanup.prototype.deleteEmptyGroups = function() {
    var groups = this.totals.groups,
        group,
        i = 0,
        progress = new Progress({
            title: "Please wait... (" + groups.length + " groups)",
            message: 'Deleting empty groups',
            min: 0,
            max: groups.length
        });
 
    // Loop through the most nested groups first
    // If the group has no layers and no groups within it, delete it
    for (; i < groups.length; i++) {
        group = groups;
        if (   group !== doc
            && group.artLayers.length === 0
            && group.layerSets.length === 0
            && !group.allLocked
            && group.linkedLayers.length === 0)
        {
            group.remove();
            this.results.groupsRemoved++;
        }
        progress.updateProgress();
    }
 
    // Close progress dialog
    progress.close();
};
 
 
// Loops through all layer compositions removing visible layers from our layers array and deleting what's left
Cleanup.prototype.findObsoleteLayers = function() {
    var comps = doc.layerComps,
        layer,
        n,
        m,
        progress = new Progress({
            title: "Please wait... (" + this.totals.numLayers + " layers)",
            message: 'Determining unused layers...',
            min: 0,
            max: comps.length * this.totals.numLayers
        });
 
    // Loop through each layer comp
    for (n = 0; n < comps.length; n++) {
        comps[n].apply();
 
        // Loop through each layer in the layer comp.
        for (m = this.totals.layers.length - 1; m > -1; m--) {
            layer = this.totals.layers[m];
 
            // If it's visible, locked, or linked, remove it from the list of possible layers to delete
            if (   layer.visible
                || layer.allLocked
                || layer.pixelsLocked
                || layer.positionLocked
                || layer.transparentPixelsLocked
                || layer.linkedLayers.length !== 0)
            {
                this.totals.layers.splice(m, 1);
            }
            // Update progress
            progress.updateProgress();
        }
    }
    progress.close();
 
    // Show new progress for deleting layers
    progress = new Progress({
        title: 'Please wait... (' + this.totals.layers.length + ' layers to delete)',
        message: 'Removing unused layers...',
        min: 0,
        max: this.totals.layers.length
    });
 
    // Save the number of layers we're deleting
    this.results.layersRemoved = this.totals.layers.length;
 
    while (this.totals.layers.length) {
        // Update progress
        progress.updateProgress();
 
        // Pop it off the array and delete it from the psd
        this.totals.layers.pop().remove();
    }
 
    // Close progress window
    progress.close();
};
 
Cleanup.prototype.summary = function() {
    alert('Summary:'
        + '\nTotal layers: ' + this.totals.numLayers
        + '\nLayers deleted: ' + this.results.layersRemoved
        + '\nTotal groups: ' + this.totals.numGroups
        + '\nEmpty groups deleted: ' + this.results.groupsRemoved);
};
 
// Adobe dialog window
var Progress = function(opts) {
    this.title = opts.title || '';
    this.message = opts.message || '';
    this.min = opts.min;
    this.max = opts.max;
    this.win = new Window('palette', this.title);
 
    // Add the progress bar
    if (this.max) {
        this.win.bar = this.win.add('progressbar', undefined, this.min, this.max);
        this.win.bar.preferredSize = [300, 20];
    }
 
    // Add a text field
    this.win.stProgress = this.win.add('statictext');
    this.win.stProgress.preferredSize.width = 230;
    this.updateText(this.message);
 
    this.win.center(this.win.parent);
    this.win.show();
    this.win.isDone = false;
};
 
// Updates the progess bar in the dialog
Progress.prototype.updateProgress = function(val) {
    var win = this.win;
    if (win.isDone) {
        return;
    }
    if (win.bar.value + val <= this.max && val !== undefined) {
        win.bar.value = val;
    } else {
        win.bar.value++;
    }
    if (win.recenter) {
        win.center(win.parentWin);
    }
    win.update();
};
 
// Updates the text in the dialog
Progress.prototype.updateText = function(text) {
    this.win.stProgress.text = text;
};
 
// Closes the dialog
Progress.prototype.close = function() {
    this.win.close();
};
 
 
// Create only one history state for the entire script
doc.suspendHistory('Cleanup Layer Comps', 'main();');
 
 
// Do it!
function main() {
    var cleanup = new Cleanup();
}

But I get error (I guess because this made for layercomps)

Could someone help me correct, it should not work alone in the layercomps?

I would like to work on documents without layercomps

Thanks in advance

regards
buga

get index without activating layer?

Post by buga »

I reread the post and I think I have not explained well.

The last code I put, I've tried with a normal document photoshop. With groups and layers (but not layercomps). The code works in principle, but not correctly and then stops working because jumps an error.

I do not know if it's a mistake on the version, but I think it is because it uses layercomps.

Could anyone help me fix it?

I have seen that the code works with a preloader. I have to study how it works. Maybe someone understands it better than me, and could explain how to use it in any other script.

I would appreciate any help

Thank you

A greeting.
pfaffenbichler

get index without activating layer?

Post by pfaffenbichler »

Code: Select allThe ID is unique?

That is, if we remove layers indexes change.
The index would be affected by removing/adding/… Layers, the ID should stick.

As for issues that have nothing to do with what the original title of the thread describes you may want to start new thread/s.