Skip to main content
Inspiring
August 19, 2018
Question

Recursive layer.getByName()

  • August 19, 2018
  • 1 reply
  • 2433 views

As built-in javascript function for Photoshop .getByName() search only at document top level, I wrote a recursive version for my personal use.

Maybe others could find it useful. It returns a javascript object containing a reference to the found layer.

It was successfully tested with Photoshop CS 6 on Mac but I'm far to be a JSX master, so this function certainly be improved.

function getLayerByName(layerName, kind, depth) {

    /*

        Gets the first layer in the document with the provided name by exploring all document's groups and sub-groups.

       

        Params:

            - layerName (string, case sensitive): required

            - kind (string): 'NORMAL', or 'TEXT', or empty (default value)

            - depth (integer): maximum groups depth to search in. 1 means document's level. 0 means no depth limit (default value)

       

        Returns a Javascript object with the following properties:

            - layer: found layer reference, or null if not found

            - name: found layer's name, or empty

            - kind: found layer's kind, or empty

            - group: boolean, true if found layer is a group

            - ingroup: boolean, true if found layer is part of a group

            - locked: boolean

            - visible: boolean

            - path: path to found layer, or empty

    */

   

    // --------------------- parameters

    depth = (isInteger(depth))? Math.abs(depth) : 0;

    kind = normalizeKind(kind) || '';

    if (typeof layerName == 'undefined' || layerName == '') return getLayersProps('', '', 'empty layer name');

   

    // --------------------- level 1 : document

    var found = false;

    try{

        var theLayer = app.activeDocument.artLayers.getByName(layerName); // found

        if (kind != '') {

            if (theLayer.kind == ('LayerKind.' + kind)) {

                found = true;

                return getLayersProps(theLayer, 'document/', '');

            }

        }else{

            found = true;

            return getLayersProps(theLayer, 'document/', '');

        }

    }catch (err){

    }

   

    // --------------------- recursive process (layers and groups)

    if (!found) return searchRecursiveLayer(layerName, app.activeDocument, depth, kind, 2, '');

}

function searchRecursiveLayer(layerName, searchObject, depth, kind, searchLevel, path) {

    var actualPath = path + searchObject.name + '/';

// alert("searchRecursiveLayer()\n\nsearch for=" + layerName + "\ndepth=" + depth + "\nkind=" + kind + "\nsearchLevel=" + searchLevel + "\nPath=" + actualPath + "\n\nsearchObject=\n" + showDebugObject(searchObject) + "\n\nlayers.length=" + searchObject.layers.length);///// for debugging

    if ((depth > 0) && (searchLevel > depth)) return getLayersProps('', actualPath, 'unable to find layer at depth ' + depth);

   

    for (var i = 0 ; i < searchObject.layers.length ; i++) { // loop through single layers or groups

        var thisLayer = searchObject.layers;

        if (thisLayer.typename == 'LayerSet') {

            try{

                var theLayer = thisLayer.artLayers.getByName(layerName); // found

                if (kind != '') {

                    if (theLayer.kind == ('LayerKind.' + kind)) return getLayersProps(theLayer, actualPath + thisLayer.name + '/', '');

                }else{

                    return getLayersProps(theLayer, actualPath + thisLayer.name + '/', '');

                }

            }catch (err){

                return searchRecursiveLayer(layerName, thisLayer, depth, kind, searchLevel + 1, actualPath);

            }

        }else{

            if (thisLayer.name == layerName) return getLayersProps(thisLayer, actualPath, ''); // found

        }

    }

    return getLayersProps('', actualPath, 'unable to find layer' + ((kind != '')? (' of kind ' + kind) : '') + ' at depth ' + depth);

}

function getLayersProps(layerRef, path, errStr) {

    errStr = errStr || '';

    path = path || '';

    var resultObject = {'layer': null, 'name': '', 'kind': '', 'group': false, 'ingroup': false, 'locked': false, 'visible': true, 'path': '', 'error': errStr};

    if (layerRef == '') return resultObject;

   

    resultObject.layer = layerRef;

    resultObject.name = layerRef.name;

    resultObject.kind = layerRef.kind;

    resultObject.group = (layerRef.typename == 'LayerSet'); // otherwise 'ArtLayer'

    resultObject.ingroup = (layerRef.parent.typename != 'Document');

    resultObject.locked = layerRef.allLocked;

    resultObject.visible = layerRef.visible;

    resultObject.path = path;

    resultObject.error = errStr;

   

    return resultObject;

}

function isInteger(value) {

    if (isNaN(parseInt(value,10)) || (parseInt(value,10) != value - 0)) return false;

    return true;

}

function normalizeKind(kind) {

    return (kind.replace(/^\s+|\s+$/g,'')).toUpperCase();

}

function normalizeKind(kind) {

    return (kind.replace(/^\s+|\s+$/g,'')).toUpperCase();

}

funct

Example:

if (app.documents.length > 0) {

    var layerToSearch = prompt('Name of layer to search for:', 'Test');

    var depth = prompt('Maximum depth to search in (0 for no depth limit):', 0);

    var kind = prompt('Layer kind to search (NORMAL | TEXT | empty):', '');

       

    var searchResult = getLayerByName(layerToSearch, kind, depth);

    alert("getLayerByName()\nName param='" + layerToSearch + "'\nKind param='" + kind + "'\nDepth param=" + depth + "\n\n" + showResultObject(searchResult));

}

function showResultObject(resultObject) { // for demo purpose

    var strResult = '';

    for (var prop in resultObject) {

        strResult += '[' + prop + '] = ' + ((Object.prototype.toString.call(resultObject[prop]) === '[object String]')? ("'" + resultObject[prop] + "'") : resultObject[prop]) + "\n";

    }

    return strResult;

}

function showDebugObject(object) { // for debug purpose

    return object + "\nname=" + ob

This topic has been closed for replies.

1 reply

frmorelAuthor
Inspiring
August 20, 2018

Another version, with layer 'type' filter: layer or group, or both

function getLayerByName(layerName, kindFilter) {

    /*

        Gets the first layer (LayerSet or ArtLayer) in the document with the provided name by exploring all document's groups and sub-groups.

       

        Params:

            - layerName (string, case sensitive): required

            - kindFilter (string): 'layer' || 'group' || 'all' || '' (empty is the default value, meaning 'all')

       

        Returns a Javascript object with the following properties:

            - layer: found layer reference, or null if not found

            - kind: 'layer', or 'group', or empty if not found

            - ingroup: boolean, true if found layer is part of a group

            - error: string describing encountered error, or empty if found

    */

   

    // --------------------- parameters

    kindFilter = kindFilter.toLowerCase() || '';

    if (kindFilter == 'all') kindFilter = '';

    if (typeof layerName == 'undefined' || layerName == '') return getLayerByName_props('', '', 'empty layer name');

   

    // --------------------- document

    try{

        var theLayer = app.activeDocument.artLayers.getByName(layerName); // found

        if (getLayerByName_concatNameType(theLayer, kindFilter) == (layerName + '_' + kindFilter)) return getLayerByName_props(theLayer, '');

    }catch (err){

    }

   

    // --------------------- recursive process (layers and groups)

    return getLayerByName_recursive(layerName, app.activeDocument, kindFilter);

}

function getLayerByName_recursive(layerName, searchObject, kindFilter) {

    for (var i = 0 ; i < searchObject.layers.length ; i++) { // loop through single layers or groups

        var thisLayer = searchObject.layers;

        if (thisLayer.typename == 'LayerSet') {

            if (getLayerByName_concatNameType(thisLayer, kindFilter) == (layerName + '_' + kindFilter)) return getLayerByName_props(thisLayer, '');

            try{

                var theLayer = thisLayer.artLayers.getByName(layerName); // found

                if (getLayerByName_concatNameType(theLayer, kindFilter) == (layerName + '_' + kindFilter)) return getLayerByName_props(theLayer, '');

            }catch (err){

                return getLayerByName_recursive(layerName, thisLayer, kindFilter);

            }

        }else{

            if (getLayerByName_concatNameType(thisLayer, kindFilter) == (layerName + '_' + kindFilter)) return getLayerByName_props(thisLayer, '');

        }

    }

   

    return getLayerByName_props('', 'unable to find ' + ((kindFilter != '')? kindFilter : 'group or layer'));

}

function getLayerByName_concatNameType(layer, kindFilter) {

    if (kindFilter == '') {

        return layer.name + '_';

    }else{

        return layer.name + '_' + ((layer.typename == 'LayerSet')? 'group' : 'layer');

    }

}

function getLayerByName_props(layerRef, errStr) {

    errStr = errStr || '';

    var resultObject = {'layer': null, 'kind': '', 'ingroup': false, 'error': errStr};

    if (layerRef == '') return resultObject;

   

    resultObject.layer = layerRef;

    resultObject.kind = ((layerRef.typename == 'LayerSet')? 'group' : 'layer'); // otherwise 'ArtLayer'

    resultObject.ingroup = (layerRef.parent.typename != 'Document');

    resultObject.error = errStr;

   

    return resultObject;

}

Example:

if (app.documents.length > 0) {

    var layerToSearch = prompt('Name of layer to search for:', 'Test');

    var kindFilter = prompt('Search for "layer" | "group" | "all" or empty', '');

       

    var searchResult = getLayerByName(layerToSearch, kindFilter);

    alert("getLayerByName()\nName param='" + layerToSearch + "'\nkindFilter param='" + kindFilter + "'\n\n" + showResultObject(searchResult));

}

function showResultObject(resultObject) { // for demo purpose

    var strResult = '';

    for (var prop in resultObject) {

        strResult += '[' + prop + '] = ' + ((Object.prototype.toString.call(resultObject[prop]) === '[object String]')? ("'" + resultObject[prop] + "'") : resultObject[prop]) + "\n";

    }

    return strResult;

}

Legend
August 20, 2018

Have you tried on a document with 300+ layers?

frmorelAuthor
Inspiring
August 20, 2018

No, I didn't...

Anyhow, I have an old machine, where everything take time, so a timer test wouldn't be very significant.