Copy link to clipboard
Copied
This code was made by Stephen Marsh to stack 3 images vertically in sequence from top to bottom in one single file. Is is possible to change it to stack any number of images? I tried doing the simple thing changing the "var setQty = 3;" to the number I wanted but it didn't do it. Would the script be able to read the number of images in a folder automatically and stack them?
https://community.adobe.com/t5/photoshop-ecosystem-discussions/how-to-merge-3-images-togehter-stacke...
/*
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
9th 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;
}
// Select the output folder
var outputFolder = Folder.selectDialog("Please select the folder to save to");
if (outputFolder === null) {
alert('Script cancelled!');
return;
}
// or
/*
// Create the output sub-directory
var outputFolder = Folder(decodeURI(inputFolder + '/Output Sets Folder'));
if (!outputFolder.exists) outputFolder.create();
*/
// Set the file processing counter
var fileCounter = 0;
// 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 name + suffix & save path
var Name = app.activeDocument.name.replace(/\.[^\.]+$/, '');
var saveFile = File(outputFolder + '/' + Name + '_x' + setQty + '-Sets' + '.psd');
// var saveFile = File(outputFolder + '/' + Name + '_x' + setQty + '-Sets' + '.jpg');
// Call the save function
savePSD(saveFile);
//saveTIFF(saveFile);
//saveJPEG(saveFile);
//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 savePSD(saveFile) {
psdSaveOptions = new PhotoshopSaveOptions();
psdSaveOptions.embedColorProfile = true;
psdSaveOptions.alphaChannels = true;
psdSaveOptions.layers = true;
psdSaveOptions.annotations = true;
psdSaveOptions.spotColors = true;
// Save as
app.activeDocument.saveAs(saveFile, psdSaveOptions, true, Extension.LOWERCASE);
}
/* Not currently used, a placeholder to swap in/out as needed
function saveTIFF(saveFile) {
tiffSaveOptions = new TiffSaveOptions();
tiffSaveOptions.embedColorProfile = true;
tiffSaveOptions.byteOrder = ByteOrder.IBM;
tiffSaveOptions.transparency = true;
// Change layers to false to save without layers
tiffSaveOptions.layers = true;
tiffSaveOptions.layerCompression = LayerCompression.ZIP;
tiffSaveOptions.interleaveChannels = true;
tiffSaveOptions.alphaChannels = true;
tiffSaveOptions.annotations = true;
tiffSaveOptions.spotColors = true;
tiffSaveOptions.saveImagePyramid = false;
// Image compression = NONE | JPEG | TIFFLZW | TIFFZIP
tiffSaveOptions.imageCompression = TIFFEncoding.TIFFLZW;
// Save as
app.activeDocument.saveAs(saveFile, tiffSaveOptions, true, Extension.LOWERCASE);
}
*/
/* Not currently used, a placeholder to swap in/out as needed
function saveJPEG(saveFile) {
jpgSaveOptions = new JPEGSaveOptions();
jpgSaveOptions.embedColorProfile = true;
jpgSaveOptions.formatOptions = FormatOptions.STANDARDBASELINE;
jpgSaveOptions.matte = MatteType.NONE;
jpgSaveOptions.quality = 10;
// Save as
activeDocument.saveAs(saveFile, jpgSaveOptions, true, Extension.LOWERCASE);
}
*/
/* Not currently used, a placeholder to swap in/out as needed
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();
}
}
// 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!');
}
Try this new script combining the vertical stacker script with a save to layered PSD:
I am happy to make changes if required.
/*
Files to Vertically Stacked Layers to PSD.jsx
https://community.adobe.com/t5/photoshop-ecosystem-discussions/edit-script-merge-multiple-scripts-together/td-p/14209166
v1.0, 5th November 2023, Stephen Marsh
Based on:
https://community.adobe.com/t5/photoshop-ecosystem-discussions/how-to-create-one-big-png-image-from-multiple-png-images/td-p/12359415
*/
...
Copy link to clipboard
Copied
The script was based around all images having the same canvas height. There was a canvas height adjustment of 300% to match the sets of 3 consistently sized images.
So, if the input stack quantity was a different number, that could be used to also create a new canvas size.
But if the images to stack are different heights, then another method would be more suitable.
I have a different script, let me dig it up...
Check the links mentioned in the comments at the head of the script:
Or this one:
Copy link to clipboard
Copied
Thank you for responding. This article you sent seems to have a script that does exactly what I need:
https://community.adobe.com/t5/photoshop-ecosystem-discussions/how-to-create-one-big-png-image-from-...
/*
Files to Vertically Stacked Layers.jsx
https://community.adobe.com/t5/photoshop-ecosystem-discussions/how-to-create-one-big-png-image-from-multiple-png-images/td-p/12359415
How to create one big PNG image from multiple PNG images?
Stephen Marsh
v1.2, 20th June 2022
*/
#target photoshop
if (app.documents.length === 0) {
(function () {
// Save the current dialog display settings
var savedDisplayDialogs = app.displayDialogs;
app.displayDialogs = DialogModes.NO;
// Capture the original ruler units and set the ruler units to pixels
var origUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
// Select the input folder
var inputFolder = Folder.selectDialog('Please select the input folder:');
// Test if Cancel button returns null, then do nothing
if (inputFolder === null) {
app.beep();
return;
}
// Supported file formats
var inputFiles = inputFolder.getFiles(/\.(jpg|jpeg|tif|tiff|png|psd|psb)$/i);
// Alpha numeric sort
// inputFiles.sort().reverse;
inputFiles.sort();
// Process the first "base" file
var firstFile = app.open(File(inputFiles[0]));
var firstFileName = app.activeDocument.name;
app.activeDocument.duplicate("Vertical-Stacker", false);
firstFile.close(SaveOptions.DONOTSAVECHANGES);
var docStack = app.documents[0];
app.activeDocument = docStack;
docStack.activeLayer.name = firstFileName;
// Process the remaining file layers to the "base" file
for (var i = 1; i < inputFiles.length; i++) {
var remainingFiles = app.open(File(inputFiles[i]));
var fileName = remainingFiles.name;
var aggregateHeight = activeDocument.height.value;
remainingFiles.activeLayer.name = fileName;
remainingFiles.layers[0].duplicate(docStack, ElementPlacement.PLACEATBEGINNING);
remainingFiles.close(SaveOptions.DONOTSAVECHANGES);
relativeCanvasSize(true, aggregateHeight);
align2SelectAll('AdCH');
align2SelectAll('AdBt');
}
app.runMenuItem(stringIDToTypeID("selectAllLayers"));
reverseLayerStack();
app.activeDocument.flatten();
app.beep();
alert(inputFiles.length + ' files vertically stacked!');
// Restore the dialogs
app.displayDialogs = savedDisplayDialogs;
// Return the original ruler units
app.preferences.rulerUnits = origUnits;
// Functions
function relativeCanvasSize(relative, height) {
var s2t = function (s) {
return app.stringIDToTypeID(s);
};
var descriptor = new ActionDescriptor();
descriptor.putBoolean(s2t("relative"), relative);
descriptor.putUnitDouble(s2t("height"), s2t("pixelsUnit"), height);
descriptor.putEnumerated(s2t("vertical"), s2t("verticalLocation"), s2t("top"));
executeAction(s2t("canvasSize"), descriptor, DialogModes.NO);
}
function align2SelectAll(method) {
app.activeDocument.selection.selectAll();
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
desc.putReference(charIDToTypeID("null"), ref);
desc.putEnumerated(charIDToTypeID("Usng"), charIDToTypeID("ADSt"), charIDToTypeID(method));
try {
executeAction(charIDToTypeID("Algn"), desc, DialogModes.NO);
} catch (e) { }
app.activeDocument.selection.deselect();
}
function reverseLayerStack() {
var idreverse = stringIDToTypeID("reverse");
var desc4653 = new ActionDescriptor();
var idnull = stringIDToTypeID("null");
var ref2335 = new ActionReference();
var idlayer = stringIDToTypeID("layer");
var idordinal = stringIDToTypeID("ordinal");
var idtargetEnum = stringIDToTypeID("targetEnum");
ref2335.putEnumerated(idlayer, idordinal, idtargetEnum);
desc4653.putReference(idnull, ref2335);
executeAction(idreverse, desc4653, DialogModes.NO);
}
})();
} else {
alert('Please close all open files before running this script...');
}
The only thing it doesn't do is ask for a folder to save the files as a .psd like the script on the original message does, how would I go about incorporating that function exactly how it is in this script?
Copy link to clipboard
Copied
It's late here so I can't offer help now... But do you want to:
(A) Learn to do this yourself
or
(B) Have it done for you
Of course, (B) could lead to (A).
Copy link to clipboard
Copied
I'd prefer B, I always learn a bit from scripts I see here and in this case, getting it and seeing it would help me out more. Of course, I hope this is not a bother to you, you can take your time, I'm not in a rush for it. Thanks a lot for the help so far!
Copy link to clipboard
Copied
Try this new script combining the vertical stacker script with a save to layered PSD:
I am happy to make changes if required.
/*
Files to Vertically Stacked Layers to PSD.jsx
https://community.adobe.com/t5/photoshop-ecosystem-discussions/edit-script-merge-multiple-scripts-together/td-p/14209166
v1.0, 5th November 2023, Stephen Marsh
Based on:
https://community.adobe.com/t5/photoshop-ecosystem-discussions/how-to-create-one-big-png-image-from-multiple-png-images/td-p/12359415
*/
#target photoshop
if (app.documents.length === 0) {
(function () {
// Save the current dialog display settings
var savedDisplayDialogs = app.displayDialogs;
app.displayDialogs = DialogModes.NO;
// Capture the original ruler units and set the ruler units to pixels
var origUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
// Select the input folder
var inputFolder = Folder.selectDialog('Please select the input folder:');
// Test if Cancel button returns null, then do nothing
if (inputFolder === null) {
app.beep();
return;
}
// Supported file formats
var inputFiles = inputFolder.getFiles(/\.(jpg|jpeg|tif|tiff|tga|png|psd|psb|webp)$/i);
// Alpha numeric sort
// inputFiles.sort().reverse;
inputFiles.sort();
// Select the output folder
var outputFolder = Folder.selectDialog("Please select the folder to save to");
if (outputFolder === null) {
alert('Script cancelled!');
return;
}
// or
/*
// Create the output sub-directory
var outputFolder = Folder(decodeURI(inputFolder + '/Output Sets Folder'));
if (!outputFolder.exists) outputFolder.create();
*/
// Process the first "base" file
var firstFile = app.open(File(inputFiles[0]));
var firstFileName = app.activeDocument.name;
app.activeDocument.duplicate("Vertical-Stacker", false);
firstFile.close(SaveOptions.DONOTSAVECHANGES);
var docStack = app.documents[0];
app.activeDocument = docStack;
docStack.activeLayer.name = firstFileName;
// Process the remaining file layers to the "base" file
for (var i = 1; i < inputFiles.length; i++) {
var remainingFiles = app.open(File(inputFiles[i]));
var fileName = remainingFiles.name;
var aggregateHeight = activeDocument.height.value;
remainingFiles.activeLayer.name = fileName;
remainingFiles.layers[0].duplicate(docStack, ElementPlacement.PLACEATBEGINNING);
remainingFiles.close(SaveOptions.DONOTSAVECHANGES);
relativeCanvasSize(true, aggregateHeight);
align2SelectAll('AdCH');
align2SelectAll('AdBt');
}
app.runMenuItem(stringIDToTypeID("selectAllLayers"));
reverseLayerStack();
//app.activeDocument.flatten();
// Restore the dialogs
app.displayDialogs = savedDisplayDialogs;
// Return the original ruler units
app.preferences.rulerUnits = origUnits;
// Save name & save path
//var Name = app.activeDocument.name.replace(/\.[^\.]+$/, '');
var saveFile = File(outputFolder + '/' + inputFiles.length + "_Vertically_Stacked_Layers.psd");
// Call the save function
savePSD(saveFile);
//activeDocument.close(SaveOptions.DONOTSAVECHANGES);
// End of script notifications
app.beep();
alert(inputFiles.length + ' files vertically stacked!');
// Functions
function relativeCanvasSize(relative, height) {
var s2t = function (s) {
return app.stringIDToTypeID(s);
};
var descriptor = new ActionDescriptor();
descriptor.putBoolean(s2t("relative"), relative);
descriptor.putUnitDouble(s2t("height"), s2t("pixelsUnit"), height);
descriptor.putEnumerated(s2t("vertical"), s2t("verticalLocation"), s2t("top"));
executeAction(s2t("canvasSize"), descriptor, DialogModes.NO);
}
function align2SelectAll(method) {
app.activeDocument.selection.selectAll();
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
desc.putReference(charIDToTypeID("null"), ref);
desc.putEnumerated(charIDToTypeID("Usng"), charIDToTypeID("ADSt"), charIDToTypeID(method));
try {
executeAction(charIDToTypeID("Algn"), desc, DialogModes.NO);
} catch (e) {}
app.activeDocument.selection.deselect();
}
function reverseLayerStack() {
var idreverse = stringIDToTypeID("reverse");
var desc4653 = new ActionDescriptor();
var idnull = stringIDToTypeID("null");
var ref2335 = new ActionReference();
var idlayer = stringIDToTypeID("layer");
var idordinal = stringIDToTypeID("ordinal");
var idtargetEnum = stringIDToTypeID("targetEnum");
ref2335.putEnumerated(idlayer, idordinal, idtargetEnum);
desc4653.putReference(idnull, ref2335);
executeAction(idreverse, desc4653, DialogModes.NO);
}
function savePSD(saveFile) {
psdSaveOptions = new PhotoshopSaveOptions();
psdSaveOptions.embedColorProfile = true;
psdSaveOptions.alphaChannels = true;
psdSaveOptions.layers = true;
psdSaveOptions.annotations = true;
psdSaveOptions.spotColors = true;
// Save as
app.activeDocument.saveAs(saveFile, psdSaveOptions, false, Extension.LOWERCASE);
}
})();
} else {
alert('Please close all open files before running this script...');
}
Copy link to clipboard
Copied
Thank you so much! it does exactly what I need!
Copy link to clipboard
Copied
You're welcome!
Get ready! An upgraded Adobe Community experience is coming in January.
Learn more