Skip to main content
Participant
February 14, 2023
Answered

Script to merge all layers with same certain names

  • February 14, 2023
  • 2 replies
  • 3749 views

Could someone help me with a script that will merge all layers with the same name, but only for certain hard coded names?

 

For example a file might contain 20 layers named "layerA", 30 layers named "layerB" and 40 layers named "layerC" > but only "layerA" and "layerB" should be merged, not "layerC". Its fine if this is hard coded into the script.

 

The big issue is that the script should iterate through all layers in the document only once, since my document has 10k layers iterating through all layers for each different name is too slow.

 

Is there a way to iterate only once through the document and use that iteration to create a dictionary that contains all groups of layers with the same name? This would then establish O(1) access for a given name, and I could then hard code a bunch of names that I want to merge.

 

Could someone help me code this? I am at a loss with the adobe script language, thanks in advance!

This topic has been closed for replies.
Correct answer r-bin
 

because I have 10k layers and it takes too long to do that

By @jack284003085p35

 

How did you manage to create 10k layers?

When the number of layers is more than 8000, problems begin with the file, not to mention the fact that adding new layers manually will not work.

Try this script. I would like to see your timings.

It won't be possible to do it faster.

 

var layers = get_layers();

merge_layers(layers, "Layer 1");
merge_layers(layers, "Layer 1 copy");

function get_layers()
    {
    try {
        $.hiresTimer;

        var layers = new Array();

        var r = new ActionReference();
        r.putProperty(stringIDToTypeID("property"), stringIDToTypeID("count"));
        r.putEnumerated(stringIDToTypeID("layer"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
        var count = executeActionGet(r).getInteger(stringIDToTypeID("count"));
        var n = 0; 
        if (!app.activeDocument.layers[app.activeDocument.layers.length-1].isBackgroundLayer) { n = 1; ++count; }

        for (var i = count-1; i >= n; i--)
            {
            var r = new ActionReference();
            r.putIndex(stringIDToTypeID("layer"), i);
            var d = executeActionGet(r);

            layers.push({id:d.getInteger(stringIDToTypeID("layerID")), name:d.getString(stringIDToTypeID("name"))});
            }

        alert("Scanned " + count + " layers in " + ($.hiresTimer/1000000).toFixed(2) + " seconds", "Timer");

        return layers;
        }
    catch (e) { alert(e); throw(e); }
    }

function merge_layers(layers, name)
    {
    try {
        $.hiresTimer;

        var len = layers.length;

        var cnt = 0;

        var r = new ActionReference();

        for (var i = 0; i < len; i++)
            {
            if (layers[i].name == name) { r.putIdentifier(stringIDToTypeID("layer"), layers[i].id); ++cnt; }
            }

        var d = new ActionDescriptor();
        d.putReference(stringIDToTypeID("null"), r);
        d.putBoolean(stringIDToTypeID("makeVisible"), false);
        executeAction(stringIDToTypeID("select"), d, DialogModes.NO); 

        alert("Selected " + cnt + " \"" + name + "\" in " + ($.hiresTimer/1000000).toFixed(2) + " seconds", "Timer");

        $.hiresTimer;

        executeAction(stringIDToTypeID("mergeLayersNew"), undefined, DialogModes.NO);

        alert("Merged " + cnt + " \"" + name + "\" in " + ($.hiresTimer/1000000).toFixed(2) + " seconds", "Timer");
        }
    catch (e) { alert(e); throw(e); }
    }

 

 

2 replies

Stephen Marsh
Community Expert
Community Expert
February 21, 2023

The layer name filter is often useful, which is the manual equivalent of scripting and the manual steps are not that taxing.

 

Participant
February 22, 2023

thanks, this of course solves the problem if i wanted to do it manually, but i want to automate it

Stephen Marsh
Community Expert
Community Expert
February 22, 2023
quote

thanks, this of course solves the problem if i wanted to do it manually, but i want to automate it


By @jack284003085p35

 

You only mentioned the need to do this for 2 sets of named layers.

 

I understand, however, there is a cost/benefit to this.

 

It would take approx. 1 minute to do this manually. The manual steps are not onerous. Multiply this however many documents need to be processed.

 

Compared to the time spent by a volunteer developing the script.

c.pfaffenbichler
Community Expert
Community Expert
February 21, 2023

Please provide a clear description of the process and a sample file (feel free to downsample it drastically). 

How many groups of identically named Layers should be merged, what are the actual target-names, …? 

Participant
February 22, 2023

i think I have it pretty well described in the post.

 

i want a script that I can hardcode something like:

 

var string = "layerA"

//code to merge all layers with name of string

 

result after running the script, all the layers that were named "layerA" are now merged into a single layer named "layerA".

 

BUT THERE CAN BE NO ITERATION, no for loop going over every single layer in the file to check if its named "layerA" ( because I have 10k layers and it takes too long to do that)

 

Maybe one iteration once to gather IDs of all layers, and then save that to a file that can be accessed to directly get the layers as if they were in an array, a surgical search instead of a brute force iteration everytime i want to merge a different name.

 

 

maybe its not possible

c.pfaffenbichler
Community Expert
Community Expert
February 22, 2023

BUT THERE CAN BE NO ITERATION, no for loop going over every single layer in the file to check if its named "layerA" ( because I have 10k layers and it takes too long to do that)

What is that supposed to mean? 

How could you check the Layers’ names other than by checking the Layers’ names? 

 

Have you tested the AM code from your thread about selecting identically named layers yet?