3 I can do with a File renamer so it's the least important one, please if you can do it without number 3
3 I can do with a File renamer so it's the least important one, please if you can do it without number 3
By @HeyoThere
Here is an updated 1.1 version, saving to a "Render" sub-folder in the input folder as PNG using a prompt for the base file name with zero padding sequential numbering:
/*
https://community.adobe.com/t5/photoshop-ecosystem-discussions/how-to-merge-3-images-togehter-stacked-in-a-batch/td-p/13922876
Stack 3 Document Sets to Vertically Stacked Layers.jsx
Stephen Marsh
v1.1 - 13th July 2023
This script requires input files from a single folder to be alpha/numeric sorting in order to stack in the correct set quantity.
*/
#target photoshop
if (!app.documents.length) {
try {
// Save and disable dialogs
var restoreDialogMode = app.displayDialogs;
app.displayDialogs = DialogModes.NO;
// Main script function
(function () {
// Select the input folder
var inputFolder = Folder.selectDialog('Please select the folder with files to process');
if (inputFolder === null) return;
// Limit the file format input, add or remove as required
var fileList = inputFolder.getFiles(/\.(png|jpg|jpeg|tif|tiff|psd|psb)$/i);
// Force alpha-numeric list sort
// Use .sort.reverse() for the first filename in the merged file
// Use .sort() for the last filename in the merged file
fileList.sort();
var setQty = 3;
// Validate that the file list is not empty
var inputCount = fileList.length;
var cancelScript1 = (inputCount === 0);
if (cancelScript1 === true) {
alert('Zero input files found, script cancelled!');
return;
}
// Validate the input count vs. output count - Thanks to Kukurykus for the advice to test using % modulus
var cancelScript2 = !(inputCount % setQty);
alert(inputCount + ' input files stacked into sets of ' + setQty + ' will produce ' + inputCount / setQty + ' output files.');
// Test if false, then terminate the script
if (cancelScript2 === false) {
alert('Script cancelled as the quantity of input files are not evenly divisible by the set quantity.');
return;
}
// Create the output sub-directory
var outputFolder = Folder(decodeURI(inputFolder + '/Render'));
if (!outputFolder.exists) outputFolder.create();
// File name prompt
var Name = prompt("Enter the base filename", "");
// Set the file processing counter
var fileCounter = 0;
// Set the sequential numbering
var numberLength = 4; // 1 to remove zero padding
var numberNo = 1; // Start number
// Loop through and open the file sets
while (fileList.length) {
// Sets of N quantity files
for (var a = 0; a < setQty; a++) {
try {
app.open(fileList.pop());
} catch (e) { }
}
// Set the base doc layer name
app.activeDocument = documents[0];
docNameToLayerName();
// Stack all open docs to the base doc
while (app.documents.length > 1) {
app.activeDocument = documents[1];
docNameToLayerName();
app.activeDocument.activeLayer.duplicate(documents[0]);
app.activeDocument = documents[0];
app.documents[1].close(SaveOptions.DONOTSAVECHANGES);
}
////////////////////////////////// Start doing stuff //////////////////////////////////
var idcanvasSize = stringIDToTypeID( "canvasSize" );
var desc295 = new ActionDescriptor();
var idheight = stringIDToTypeID( "height" );
var idpercentUnit = stringIDToTypeID( "percentUnit" );
desc295.putUnitDouble( idheight, idpercentUnit, 300.000000 );
var idvertical = stringIDToTypeID( "vertical" );
var idverticalLocation = stringIDToTypeID( "verticalLocation" );
var idtop = stringIDToTypeID( "top" );
desc295.putEnumerated( idvertical, idverticalLocation, idtop );
executeAction(idcanvasSize, desc295, DialogModes.NO);
activeDocument.selection.selectAll();
var idselect = stringIDToTypeID( "select" );
var desc393 = new ActionDescriptor();
var idnull = stringIDToTypeID( "null" );
var ref95 = new ActionReference();
var idlayer = stringIDToTypeID( "layer" );
var idordinal = stringIDToTypeID( "ordinal" );
var idbackwardEnum = stringIDToTypeID( "backwardEnum" );
ref95.putEnumerated( idlayer, idordinal, idbackwardEnum );
desc393.putReference( idnull, ref95 );
var idmakeVisible = stringIDToTypeID( "makeVisible" );
desc393.putBoolean( idmakeVisible, false );
var idlayerID = stringIDToTypeID( "layerID" );
var list14 = new ActionList();
list14.putInteger( 3 );
desc393.putList( idlayerID, list14 );
executeAction(idselect, desc393, DialogModes.NO);
var idalign = stringIDToTypeID( "align" );
var desc396 = new ActionDescriptor();
var idnull = stringIDToTypeID( "null" );
var ref96 = new ActionReference();
var idlayer = stringIDToTypeID( "layer" );
var idordinal = stringIDToTypeID( "ordinal" );
var idtargetEnum = stringIDToTypeID( "targetEnum" );
ref96.putEnumerated( idlayer, idordinal, idtargetEnum );
desc396.putReference( idnull, ref96 );
var idusing = stringIDToTypeID( "using" );
var idalignDistributeSelector = stringIDToTypeID( "alignDistributeSelector" );
var idADSCentersV = stringIDToTypeID( "ADSCentersV" );
desc396.putEnumerated( idusing, idalignDistributeSelector, idADSCentersV );
var idalignToCanvas = stringIDToTypeID( "alignToCanvas" );
desc396.putBoolean( idalignToCanvas, false );
executeAction(idalign, desc396, DialogModes.NO);
var idselect = stringIDToTypeID( "select" );
var desc393 = new ActionDescriptor();
var idnull = stringIDToTypeID( "null" );
var ref95 = new ActionReference();
var idlayer = stringIDToTypeID( "layer" );
var idordinal = stringIDToTypeID( "ordinal" );
var idbackwardEnum = stringIDToTypeID( "backwardEnum" );
ref95.putEnumerated( idlayer, idordinal, idbackwardEnum );
desc393.putReference( idnull, ref95 );
var idmakeVisible = stringIDToTypeID( "makeVisible" );
desc393.putBoolean( idmakeVisible, false );
var idlayerID = stringIDToTypeID( "layerID" );
var list14 = new ActionList();
list14.putInteger( 3 );
desc393.putList( idlayerID, list14 );
executeAction(idselect, desc393, DialogModes.NO);
var idalign = stringIDToTypeID( "align" );
var desc399 = new ActionDescriptor();
var idnull = stringIDToTypeID( "null" );
var ref98 = new ActionReference();
var idlayer = stringIDToTypeID( "layer" );
var idordinal = stringIDToTypeID( "ordinal" );
var idtargetEnum = stringIDToTypeID( "targetEnum" );
ref98.putEnumerated( idlayer, idordinal, idtargetEnum );
desc399.putReference( idnull, ref98 );
var idusing = stringIDToTypeID( "using" );
var idalignDistributeSelector = stringIDToTypeID( "alignDistributeSelector" );
var idADSBottoms = stringIDToTypeID( "ADSBottoms" );
desc399.putEnumerated( idusing, idalignDistributeSelector, idADSBottoms );
var idalignToCanvas = stringIDToTypeID( "alignToCanvas" );
desc399.putBoolean( idalignToCanvas, false );
executeAction(idalign, desc399, DialogModes.NO);
activeDocument.selection.deselect();
////////////////////////////////// Finish doing stuff //////////////////////////////////
// Delete XMP metadata to reduce final file size of output files
removeXMP();
// Save path, name + zero pad suffix
var saveFile = File(outputFolder + '/' + Name + "_" + zeroPad(numberNo, numberLength) + '.png');
// Increment the file number
numberNo++;
// Call the save function
savePNG(saveFile);
// Close all open files without saving
while (app.documents.length) {
app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
}
// Increment the file saving counter
fileCounter++;
///// Functions /////
function savePNG(saveFile) {
var pngOptions = new PNGSaveOptions();
pngOptions.compression = 0; // 0-9
pngOptions.interlaced = false;
// Save as
app.activeDocument.saveAs(saveFile, pngOptions, true, Extension.LOWERCASE);
}
function docNameToLayerName() {
var layerName = app.activeDocument.name.replace(/\.[^\.]+$/, '');
app.activeDocument.activeLayer.name = layerName;
}
function removeXMP() {
if (!documents.length) return;
if (ExternalObject.AdobeXMPScript == undefined) ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");
var xmp = new XMPMeta(activeDocument.xmpMetadata.rawData);
XMPUtils.removeProperties(xmp, "", "", XMPConst.REMOVE_ALL_PROPERTIES);
app.activeDocument.xmpMetadata.rawData = xmp.serialize();
}
}
function zeroPad(num, digit) {
var tmp = num.toString();
while (tmp.length < digit) {
tmp = "0" + tmp;
}
return tmp;
}
// Restore saved dialogs
app.displayDialogs = restoreDialogMode;
// End of script notification
app.beep();
alert('Script completed!' + '\n' + fileCounter + ' combined files saved to:' + '\n' + outputFolder.fsName);
// Open the output folder in the Finder or Explorer
// outputFolder.execute();
}());
} catch (e) {
// Restore saved dialogs
app.displayDialogs = restoreDialogMode;
alert("If you see this message, something went wrong!" + "\r" + e + ' ' + e.line);
}
}
else {
alert('Stack 3 Document Sets to Vertically Stacked Layers:' + '\n' + 'Please close all open documents before running this script!');
}
NOTE: I am not currently checking for or cleaning illegal characters in the file base name.