Skip to main content
Known Participant
May 9, 2019
Question

Copy All Layers From Template Document

  • May 9, 2019
  • 3 replies
  • 2636 views

I was wondering if there is a script out there that would copy all the layers from a template file "Layer_Template" in this case to a currently open file. I've looked but come up empty. My scripting skill is pretty low, even something that could point me in the right direction would be appreciated.

This topic has been closed for replies.

3 replies

Stephen Marsh
Community Expert
Community Expert
May 11, 2019

Please give the following script a try. I'm only a scripting beginner, so the code is ugly, but it works. All of the source layers from the template layer file will then be added to the destination file. This script is based upon the principles mentioned in my previous posts.

All you need to do is replace the filepath & filename '~/Desktop/Layer_Template.psd' on line 28 to match your template layer file's location.

This script can be recorded into an action and can then be batch processed via the Image Processor or Image Processor Pro scripts. No manual user intervention is required with this script, it is all automated.

Additional code could be added to this script to perform the batch processing and saving to make the code self-contained rather than relying on the IP or IPP scripts.

#target Photoshop

// Copy All Layers From Template Document

// https://forums.adobe.com/message/11069602

displayDialogs = DialogModes.NO 

// Create a target layer for smart object 

// app.activeDocument.artLayers.add(); 

// app.activeDocument.activeLayer.name = 'smartObject_Target'; 

app.activeDocument.artLayers.add().name = 'smartObject_Target'; 

 

// Place the Layer_Template file as an embedded smart object layer 

placeEvent(); 

function placeEvent() { 

  var c2t = function (s) { 

  return app.charIDToTypeID(s); 

  }; 

 

  var s2t = function (s) { 

  return app.stringIDToTypeID(s); 

  }; 

 

  var descriptor = new ActionDescriptor(); 

  var descriptor2 = new ActionDescriptor(); 

 

  descriptor.putInteger(s2t("ID"), 13); 

  descriptor.putPath(c2t("null"), new File('~/Desktop/Layer_Template.psd')); // Layer_Template document file path 

  descriptor.putEnumerated(s2t("freeTransformCenterState"), s2t("quadCenterState"), s2t("QCSAverage")); 

  descriptor2.putUnitDouble(s2t("horizontal"), s2t("pixelsUnit"), 0.000000); 

  descriptor2.putUnitDouble(s2t("vertical"), s2t("pixelsUnit"), 0.000000); 

  descriptor.putObject(s2t("offset"), s2t("offset"), descriptor2); 

  executeAction(s2t("placeEvent"), descriptor, DialogModes.NO); 

 

// Change the smart object layer name 

app.activeDocument.activeLayer.name = 'smartObject_Target'; 

// Name the active doc in preparation for targeting the smart object layers

var targetDoc = app.activeDocument;

 

// Edit the smart object layer contents 

app.runMenuItem(stringIDToTypeID('placedLayerEditContents')); 

 

// Expand all layer sets 

// https://forums.adobe.com/message/5764024#5764024 

function openAllLayerSets(parent) { 

    for (var setIndex = 0; setIndex < parent.layerSets.length; setIndex++) { 

        app.activeDocument.activeLayer = parent.layerSets[setIndex].layers[0]; 

        openAllLayerSets(parent.layerSets[setIndex]); 

    } 

}; 

openAllLayerSets(app.activeDocument); 

 

// Select all layers and layer groups/sets! 

// https://feedback.photoshop.com/photoshop_family/topics/i-cant-record-sellect-all-layers-in-script-listener-and-in-actions 

selectAllLayers(); 

function selectAllLayers() { 

    var c2t = function(s) { 

        return app.charIDToTypeID(s); 

    }; 

 

    var s2t = function(s) { 

        return app.stringIDToTypeID(s); 

    }; 

 

    var descriptor = new ActionDescriptor(); 

    var descriptor2 = new ActionDescriptor(); 

    var reference = new ActionReference(); 

    var reference2 = new ActionReference(); 

 

    reference2.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum")); 

    descriptor.putReference(c2t("null"), reference2); 

    executeAction(s2t("selectAllLayers"), descriptor, DialogModes.NO); 

    reference.putProperty(s2t("layer"), s2t("background")); 

    descriptor2.putReference(c2t("null"), reference); 

    descriptor2.putEnumerated(s2t("selectionModifier"), s2t("selectionModifierType"), s2t("addToSelection")); 

    descriptor2.putBoolean(s2t("makeVisible"), false); 

    try { 

        executeAction(s2t("select"), descriptor2, DialogModes.NO); 

    } catch (e) {} 

 

// Duplicate the edited smart object layers to the original file 

app.activeDocument.activeLayer.duplicate(targetDoc) 

 

// Close the edited smart object layer document without saving changes 

app.activeDocument.close(SaveOptions.DONOTSAVECHANGES); 

 

// Remove the smart object layer as it was only a means to an end 

app.activeDocument.layers.getByName('smartObject_Target').remove();

JJMack
Community Expert
Community Expert
May 11, 2019

I think I would have have just retrieved the current document into named file object like CurrentDoc.   Opened the template file got its canvas size width and height in Pixels selected all layers using action manager code menu select>Select all Layers   and duplicated Layers to the  currentdoc object then closed the template document. Compared the CurrentDocument canvas size to the templates canvas size and expand the canvas if the templates canvas size was large.  You script may leaves all the Template layers clipped by the first document canvas size I believe.

Place is also a tricky feature to play with in a script.  Place may resize the objects   because of Print resolution and may scale the smart object layer created.  However,  if you Open the object the original template files object will be opened and the canvas size may larger than the smart object layer the you open the object from because  of the resizing and scaling place may have done.  Place is also used in other Photoshop features like Replace Contents and Photoshop new Frame  layers.  I believe some of Adobe's issues with the Frame Tool is caused by Adobe use of Place.

JJMack
Stephen Marsh
Community Expert
Community Expert
May 11, 2019

I'd prefer to see your code JJ than read about what you would have done, but did not do :/

The flaw with the select all layers command is that it does not select a background layer, so it is not bulletproof. The "convoluted" code used to select all layers in my script does not have this limitation when working with files that may contain unknown content such as a background layer.

Yes, my code does presume that general prefs are set for "Resize image during place", otherwise, yes, if the target document canvas is smaller the layer content will be clipped.

The OP did state:

The size of the images being combined would always be the same so the canvas issue shouldn't be a problem.
Stephen Marsh
Community Expert
Community Expert
May 11, 2019

One option in the short term, you can manually or via an action select all required layers in the source file, then use the Layer > Duplicate Layers command to move them to your destination file.

This general approach can be scripted, with various methods of selecting all layers, as it can become trickier once layers, layer sets, background image layers etc. come into play in different layer stack orders:

https://forums.adobe.com/thread/2585105

https://feedback.photoshop.com/photoshop_family/topics/i-cant-record-sellect-all-layers-in-script-listener-and-in-actions

Or perhaps an action or script could place the template layer file as a smart object, then move the layers from the smart object to the destination file.

JJMack
Community Expert
Community Expert
May 11, 2019

The OP first need to decide what they want to do.  Which of the two question they asked the want to automate  or if they want to automate both question. Actions can not be use to resolve either question.

JJMack
Stephen Marsh
Community Expert
Community Expert
May 11, 2019

The OP first need to decide what they want to do. Which of the two question they asked the want to automate  or if they want to automate both question

I agree. The first option is probably easier than the second for somebody with limited scripting skills, at least that is where I would start.

Actions can not be use to resolve either question.

An action can not offer a fully automated workflow, however, they can greatly speed up the process and semi-automate the task.

So what to do? Wait for help and the generosity of others and suffer through doing everything manually?

Or at least automate 99% of the process in the short term until a better solution comes along?

I would choose to at least semi-automate the process as much as possible with an action and batch/image processor/image processor pro!

One such example of a few different possibilities below:

Step 1:  fully automated with the Image Processor script to save multiple PSD files with the template layer as a smart object layer using the Batch 1 action:

Step 2: Using the Batch 2 action, there are only two manual GUI selections per batched image via the Image Processor – selecting the target document dropdown menu and pressing OK:

This could be performed in a single action, however by splitting into two actions, the first action can be fully automated, while the second action contains the single step that required two manual GUI selections per image, everything else is fully automated.

This is not as good as a script, however does reduce a tedius manual task from 20-30 seconds per image down to 1-2 seconds per image – with the only manual input being a mouse move to select a dropdown menu item and the press of the return/enter key per image.

Known Participant
May 9, 2019

Or possibly a folder of files as well. (Sorry for the add)

JJMack
Community Expert
Community Expert
May 10, 2019

Both would be easy to script.  You would most likely want to limit the Files process from a folder to some list of Image file type and  know how you want to handle layered image file in the folder.   Also Templates  image files and and other image files cans have any size  canvases and layers in a layered document can be any size. Photoshop also has a limit of 8,000 layers. So Layers you copy into your open document may be clipped by your document's canvas size.

If you have an open document a script can get the open document name. Then the script could open the template file select all layer and use duplicate layers into the open document you started the script from. Once the layer are duplicated the script would close the template document and end.

JJMack
Known Participant
May 10, 2019

I found the following script by c.pfaffenbichler

which is pretty close to what I'm looking for.

Would it be possible to modify it so that it just refers to a static file (the template file) and doesn't require a matching amount of files in both folders? The size of the images being combined would always be the same so the canvas issue shouldn't be a problem.

#target photoshop

// dialog for folder-selection;

var theFolderOne = Folder.selectDialog ("select a folder containing the backgoround images");

var theFolderTwo = Folder.selectDialog ("select a folder containing the foreground images");

var theFolderThree = Folder.selectDialog ("select a folder to save the combined images to");

if (theFolderOne && theFolderTwo && theFolderThree) {

var theFilesOne = theFolderOne.getFiles(checkFor);

var theFilesTwo = theFolderTwo.getFiles(checkFor);

// check if both folders contain the same number of files;

if (theFilesOne.length != theFilesTwo.length) {

alert ("the folders don’t contain the same number of images")

}

// else do the stuff;

else {

// create the psd-options;

psdOpts = new PhotoshopSaveOptions();

psdOpts.embedColorProfile = true;

psdOpts.alphaChannels = false;

psdOpts.layers = true;

psdOpts.spotColors = true;

// run through the files;

for (var a  = 0; a < theFilesOne.length; a++) {

// open background-image;

var theFile = app.open(File(theFilesOne));

theFile.activeLayer = theFile.layers[0];

// place foreground-image;

var idPlc = charIDToTypeID( "Plc " );

var desc6 = new ActionDescriptor();

var idAs = charIDToTypeID( "As  " );

var desc7 = new ActionDescriptor();

var idfsel = charIDToTypeID( "fsel" );

var idpdfSelection = stringIDToTypeID( "pdfSelection" );

var idpage = stringIDToTypeID( "page" );

desc7.putEnumerated( idfsel, idpdfSelection, idpage );

var idPgNm = charIDToTypeID( "PgNm" );

desc7.putInteger( idPgNm, 1 );

var idCrop = charIDToTypeID( "Crop" );

var idcropTo = stringIDToTypeID( "cropTo" );

var idboundingBox = stringIDToTypeID( "boundingBox" );

desc7.putEnumerated( idCrop, idcropTo, idboundingBox );

var idPDFG = charIDToTypeID( "PDFG" );

desc6.putObject( idAs, idPDFG, desc7 );

var idnull = charIDToTypeID( "null" );

desc6.putPath( idnull, new File( theFilesTwo ) );

var idFTcs = charIDToTypeID( "FTcs" );

var idQCSt = charIDToTypeID( "QCSt" );

var idQcsa = charIDToTypeID( "Qcsa" );

desc6.putEnumerated( idFTcs, idQCSt, idQcsa );

var idOfst = charIDToTypeID( "Ofst" );

var desc8 = new ActionDescriptor();

var idHrzn = charIDToTypeID( "Hrzn" );

var idRlt = charIDToTypeID( "#Rlt" );

desc8.putUnitDouble( idHrzn, idRlt, 0.000000 );

var idVrtc = charIDToTypeID( "Vrtc" );

var idRlt = charIDToTypeID( "#Rlt" );

desc8.putUnitDouble( idVrtc, idRlt, 0.000000 );

var idOfst = charIDToTypeID( "Ofst" );

desc6.putObject( idOfst, idOfst, desc8 );

var idAntA = charIDToTypeID( "AntA" );

desc6.putBoolean( idAntA, true );

executeAction( idPlc, desc6, DialogModes.NO );

// save the combined files;

theFile.saveAs(new File (theFolderThree + "/file" + bufferNumberWithZeros((a + 1), 4) ), psdOpts)

theFile.close(SaveOptions.DONOTSAVECHANGES)

}

}

};

////////////////////////////////////

////// check for psd, tif or jpg //////

function checkFor (theFile) {

if (theFile.name.slice(-4) == ".psd" || theFile.name.slice(-4) == ".tif" || theFile.name.slice(-4) == ".jpg") {return true}

else {return false}

};

////// buffer number with zeros //////

function bufferNumberWithZeros (number, places) {

var theNumberString = String(number);

for (var o = 0; o < (places - String(number).length); o++) {

theNumberString = String("0" + theNumberString)

};

return theNumberString

};