Skip to main content
Participating Frequently
April 5, 2023
Question

Script to merge top layer to each layer below

  • April 5, 2023
  • 5 replies
  • 3444 views

The Task is to have a codesnippet that i can inject in other scripts for Photoshop doing the following:

Merge the first Layer (also possible to have a fixed name e.g. "WATERMARK")

on each layer below (picture 1 to picture 100).
The names of the layers should still be the same as they where before merging. 

 

can anyone help me with this?

i know that i can do an action for this and batchprocess this task, but i have a script running that only misses that one step before saving all the files with their correct name + adding width_x_height_px. 

 

thanks in advance

 

This topic has been closed for replies.

5 replies

c.pfaffenbichler
Community Expert
April 5, 2023

// merge copies of layer named "watermark" to all other layers;
// 2023, use it at your own risk;
if (app.documents.length > 0) {
// revert for testing;
    executeAction( stringIDToTypeID( "revert" ), undefined, DialogModes.NO );
    var theLayers = collectLayersAndLayerOfName("watermark");
    var theseLayers = theLayers[1];
// process layers;
    if (theLayers[0].length == 1) {
        for (var m = theseLayers.length - 1; m >= 0; m--) {
            if (isSmartObject(theseLayers[m][2]) == true) {
                rasterizeSmartObject(theseLayers[m][2]);
            };
            duplicateMoveLayerTo (theLayers[0][0][2], theseLayers[m][2]);
// merge;
            var desc2 = new ActionDescriptor();
            executeAction( stringIDToTypeID( "mergeLayersNew" ), desc2, DialogModes.NO );
        }
    } else {alert ("please do it properly")}
};
////////////////////////////////////
////// collect layers and layer with certain name //////
function collectLayersAndLayerOfName (waterMark) {
// get number of layers;
    var ref = new ActionReference();
    ref.putProperty(stringIDToTypeID('property'), stringIDToTypeID('numberOfLayers'));
    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 theWaterMarks = 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 (layerSet != "layerSectionEnd" && layerSet != "layerSectionStart" && isBackground != true) {
    var theName = layerDesc.getString(stringIDToTypeID('name'));
    var theID = layerDesc.getInteger(stringIDToTypeID('layerID'));
    var theIndex = layerDesc.getInteger(stringIDToTypeID('itemIndex'));
    var isSmartObject = layerDesc.hasKey(stringIDToTypeID("smartObject"));
// check name;
    if (theName == waterMark) {theWaterMarks.push([theName, theIndex, theID, isSmartObject])}
    else {theLayers.push([theName, theIndex, theID, isSmartObject])};
    };
    }
    catch (e) {};
    }
    return [theWaterMarks, theLayers]
    };
////// based on code by mike hale and paul riggott //////
function selectLayerByID(theID,add){ 
    add = undefined ? add = false:add 
    var ref = new ActionReference();
        ref.putIdentifier(charIDToTypeID("Lyr "), theID);
        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); 
    }
    };
////// move active layer in front of other layer in layer stack //////
function duplicateMoveLayerTo (thisLayerId, targetId) {
       selectLayerByID(thisLayerId, false);
    var idlayer = stringIDToTypeID( "layer" );
        var desc58 = new ActionDescriptor();
            var ref19 = new ActionReference();
            ref19.putEnumerated( idlayer, stringIDToTypeID( "ordinal" ), stringIDToTypeID( "targetEnum" ) );
        desc58.putReference( stringIDToTypeID( "null" ), ref19 );
            var ref20 = new ActionReference();
            ref20.putIndex( idlayer, getLayerIndex(targetId)+1 );
        desc58.putReference( stringIDToTypeID( "to" ), ref20 );
        desc58.putBoolean( stringIDToTypeID( "adjustment" ), false );
        desc58.putInteger( stringIDToTypeID( "version" ), 5 );
            var list11 = new ActionList();
            list11.putInteger(thisLayerId);
        desc58.putList( stringIDToTypeID( "layerID" ), list11 );
        desc58.putBoolean( stringIDToTypeID( "duplicate" ), true );
    executeAction( stringIDToTypeID( "move" ), desc58, DialogModes.NO );
    };
////// by mike hale, via paul riggott //////
function getLayerIndex(theId){
    var ref = new ActionReference(); 
    ref.putProperty(stringIDToTypeID('property'), stringIDToTypeID('itemIndex'));
    ref.putIdentifier(charIDToTypeID("Lyr "), theId); 
    d = executeActionGet(ref);
    return (d.getInteger(stringIDToTypeID('itemIndex'))-1); 
    }; 
////// is smart object //////
function isSmartObject (theId) {
    var ref = new ActionReference();
    ref.putProperty (stringIDToTypeID ("property"), stringIDToTypeID ("smartObject"));
    ref.putIdentifier( charIDToTypeID("Lyr "), theId );
    var layerDesc = executeActionGet(ref);
    var isSmartObject = layerDesc.hasKey(stringIDToTypeID("smartObject"));
    return isSmartObject
};
////// rasterize the so //////
function rasterizeSmartObject (aLayer) {
selectLayerByID(aLayer, false);
// rasterize the so;
try {
var desc125 = new ActionDescriptor(); 
var ref83 = new ActionReference(); 
ref83.putEnumerated( charIDToTypeID( "Mn  " ), charIDToTypeID( "MnIt" ), stringIDToTypeID( "rasterizePlaced" ) );
desc125.putReference( charIDToTypeID( "null" ), ref83 ); 
executeAction( charIDToTypeID( "slct" ), desc125, DialogModes.NO );
return app.activeDocument.activeLayer
} catch (e) {alert (e)}
};
Participating Frequently
April 5, 2023

your script does the action 1 time - deletes all the other layers - and then tells me to do it properly 🙂 ,
i have a layer called watermark (all smallcaps) - what am i missing? do the layers need to have a specific name? or do they need to be in a "Group1" Folder? Thanks for your time btw..i really aprecciate it!. 

Stephen Marsh
Community Expert
April 5, 2023

@defaultzgaeia0p3ind 

 

Try this script, it works with groups and smart objects (which are merged) and offers a single history step. The WATERMARK layer is removed, however, it can be easily retained if you prefer to keep it.

 

 

/*
Apply Watermark Layer to All Layers.jsx
v1.0 - 5th April 2023, Stephen Marsh
https://community.adobe.com/t5/photoshop-ecosystem-discussions/script-to-merge-top-layer-to-each-layer-below/td-p/13704761
*/

#target photoshop

function main() {
    if (!documents.length) {
        alert('There are no documents open!');
    
    } else {
        //activeDocument.activeLayer = activeDocument.layers["WATERMARK"];
        selectWatermarkLayer("WATERMARK");
        activeDocument.selection.selectAll();
        activeDocument.selection.copy();
        activeDocument.selection.deselect();
        activeDocument.activeLayer.remove();
        processAllLayersAndSets(app.activeDocument);
    }

    function processAllLayersAndSets(obj) {
        // Process Layers 
        for (var i = obj.artLayers.length - 1; 0 <= i; i--) {
            app.activeDocument.activeLayer = obj.artLayers[i];
            applyWatermarkLayer();
        }
        // Process Layer Set Layers 
        for (var i = obj.layerSets.length - 1; 0 <= i; i--) {
            processAllLayersAndSets(obj.layerSets[i]);
        }
    }

    function applyWatermarkLayer() {
        activeDocument.paste();
        selectActAndPrevLayers();
        groupFromLayers();
        var theName = activeDocument.activeLayer.layers[activeDocument.activeLayer.layers.length - 1].name;
        activeDocument.activeLayer.name = theName;
        activeDocument.activeLayer.merge();
    }

    app.purge(PurgeTarget.CLIPBOARDCACHE);
}

activeDocument.suspendHistory('Apply Watermark Layer to All Layers...', 'main()');


///// FUNCTIONS /////

function selectActAndPrevLayers() {
	function s2t(s) {
        return app.stringIDToTypeID(s);
    }
	var descriptor = new ActionDescriptor();
	var list = new ActionList();
	var reference = new ActionReference();
	reference.putEnumerated( s2t( "layer" ), s2t( "ordinal" ), s2t( "backwardEnum" ));
	descriptor.putReference( s2t( "null" ), reference );
	descriptor.putEnumerated( s2t( "selectionModifier" ), s2t( "selectionModifierType" ), s2t( "addToSelection" ));
	descriptor.putBoolean( s2t( "makeVisible" ), false );
	descriptor.putList( s2t( "layerID" ), list );
	executeAction( s2t( "select" ), descriptor, DialogModes.NO );
}

function groupFromLayers() {
	function s2t(s) {
		return app.stringIDToTypeID(s);
	}
	var descriptor = new ActionDescriptor();
	var descriptor2 = new ActionDescriptor();
	var reference = new ActionReference();
	var reference2 = new ActionReference();
	reference.putClass( s2t( "layerSection" ));
	descriptor.putReference( s2t( "null" ), reference );
	reference2.putEnumerated( s2t( "layer" ), s2t( "ordinal" ), s2t( "targetEnum" ));
	descriptor.putReference( s2t( "from" ), reference2 );
	descriptor2.putString( s2t( "name" ), "Temp" );
	descriptor.putObject( s2t( "using" ), s2t( "layerSection" ), descriptor2 );
	descriptor.putString( s2t( "name" ), "Temp" );
	executeAction( s2t( "make" ), descriptor, DialogModes.NO );
}

function selectWatermarkLayer(theLayerName) {
    // Works even if no layers are currently selected!
	function s2t(s) {
		return app.stringIDToTypeID(s);
	}
	var descriptor = new ActionDescriptor();
	var list = new ActionList();
	var reference = new ActionReference();
	reference.putName( s2t( "layer" ), theLayerName );
	descriptor.putReference( s2t( "null" ), reference );
	descriptor.putBoolean( s2t( "makeVisible" ), false );
	list.putInteger( 15 );
	descriptor.putList( s2t( "layerID" ), list );
	executeAction( s2t( "select" ), descriptor, DialogModes.NO );
}

 

  1. Copy the code text to the clipboard
  2. Open a new blank file in a plain-text editor (not in a word processor)
  3. Paste the code in
  4. Save as a plain text format file – .txt
  5. Rename the saved file extension from .txt to .jsx
  6. Install or browse to the .jsx file to run (see below)

https://prepression.blogspot.com/2017/11/downloading-and-installing-adobe-scripts.html#Photoshop

 

Participating Frequently
April 5, 2023

Your Script works like a charm.. in the meantime i tried to get CHATGPT to do something similar.. but it produced errors .. yours works on the first try and does exactly what i wanted.. want to try @c.pfaffenbichler Version now. 🙂 thank so much for your time and effort 

c.pfaffenbichler
Community Expert
April 5, 2023
quote

in the meantime i tried to get CHATGPT to do something similar.. 

I consider this approach not sensible at current. 

Stephen Marsh
Community Expert
April 5, 2023

@defaultzgaeia0p3ind - I'd suggest cropped screenshots of the layers panel, before and after... And or a sample PSD layered file to clearly illustrate your post.

 

Edit: are your layers inside one or more groups/artboards/frames?

Participating Frequently
April 5, 2023

does that help?
you see the "watermark" layer - i need this to be merged with all the layers below.. indivdual. and keep the name of the lower layers

Participating Frequently
April 5, 2023

dont get distracted by the smartobjects.. or folders.. it could also be flat layers and no folders

c.pfaffenbichler
Community Expert
April 5, 2023

Anyway, which part of the process gives you problems in Scripting? 

Participating Frequently
April 5, 2023

My merge down does the following

c.pfaffenbichler
Community Expert
April 5, 2023

Not mentioning relevant details makes it hard to get meaningful advice. 

You had mentioned neither Groups nor Smart Objects. 

c.pfaffenbichler
Community Expert
April 5, 2023

Then you need to duplicate the top Layer times the number of other layers, move one duplicate in front of each of those other layers and merge. 

Selecting a Layer and merging it to the Layer below should maintain the lower Layer’s name anyway. 

Participating Frequently
April 5, 2023

thanks for your reply - adding a layer on top and merging, gives the new layer the same name as the layer on top 😉

c.pfaffenbichler
Community Expert
April 5, 2023

Not here.