Skip to main content
Known Participant
June 26, 2023
Answered

How to automatically add two images into layer in a single PSD or TIFF then save?

  • June 26, 2023
  • 6 replies
  • 5074 views

Can someone help me how to perform this process?

Automatically combine two images into one layered PSD or TIFF image, then save.
Let's say I have a bunch of original images and retouched images in a folder.
Like this,

image_01.tiff

image_01_retouched.tiff

image_02.tiff

image_02_retouched.tiff
I would like some kind of script to automatically add retouched image into the second layer in the original image and then save the file. (It would be amazing if it could also change the file names as well)
Is this possible?

I'm doing this manually, and as you can guess, it's painful.
By opening both images and dragging the retouched image into the original image. Then save the file.

 

Correct answer Stephen Marsh

Hi @Stephen Marsh 

Your example is correct, but here are a few real file names.
526842A-Black_MC_068-top.tif
526842A-Black_MC_068.tif
8542156C-Red_MC_022-top.tif
8542156C-Red_MC_022.tif

If I run the script as they are, the layer order will flip in the stacked file.
If I change the hyphen to underscore, everything works perfectly. 
The top layer file is automatically generated; I can't change it to underscore when generated.
I can only rename them afterward, but I want to see if I can skip that step if possible.



quote

Hi @Stephen Marsh 

If I run the script as they are, the layer order will flip in the stacked file.


By @hosongn52153496

 

Find the following section in the code:

 

// Force alpha-numeric list sort
// Use .reverse() for the first filename in the merged file
// Remove .reverse() for the last filename in the merged file
fileList.sort().reverse();

 

Then change the last line #36 to:

 

// Force alpha-numeric list sort
// Use .reverse() for the first filename in the merged file
// Remove .reverse() for the last filename in the merged file
fileList.sort();

 

Does that fix the layer order issue?

6 replies

Stephen Marsh
Community Expert
Community Expert
January 22, 2025

On a related note, I built a generic script with a GUI – "Stack Documents to Sets of N Layers" (this script doesn't retain the Background layer of the first doc, the expectation is that files are flattened or have single layers):

 

 

https://community.adobe.com/t5/photoshop-ecosystem-discussions/script-to-automate-load-files-into-stack/m-p/13499068#U14928257

 

Stephen Marsh
Community Expert
Community Expert
June 28, 2023

@hosongn52153496 

 

I have cleaned up the code a little bit from the generic script previously posted and changed over to layered TIFF output:

 

/* 

Stack x2 Image Sets to Layered TIFF.jsx
https://community.adobe.com/t5/photoshop-ecosystem-discussions/how-to-automatically-add-two-images-into-layer-in-a-single-psd-or-tiff-then-save/m-p/13897545
v1.0 - 28th June 2023, Stephen Marsh

* This script requires input files from a single folder to be alpha/numeric sorting in order to stack in the correct set quantity. 

* A minimum of 2 or more files per stack is required. The quantity of input files must be evenly divisible by the stack 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 .reverse() for the first filename in the merged file
            // Remove .reverse() for the last filename in the merged file
            fileList.sort().reverse();

            // Set Quantity
            var setQty = 2;

            // 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;
            }

            // Set the file processing counter
            var fileCounter = 0;

            // Loop through and open the file sets
            while (fileList.length) {
                // Sets of 2 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);
                }

                // 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' + '.tif');

                // Call the save function
                saveTIFF(saveFile);

                // Close all open files without saving
                while (app.documents.length) {
                    app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
                }

                // Increment the file saving counter
                fileCounter++;


                ///// Functions /////


                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);
                }

                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 x2 Image Sets Sets to Layers:' + '\n' + 'Please close all open documents before running this script!');
}

 

Known Participant
June 28, 2023

Thank you so much @Stephen Marsh !!
You are Magic!

Stephen Marsh
Community Expert
Community Expert
June 28, 2023

@hosongn52153496 - You're welcome!

Stephen Marsh
Community Expert
Community Expert
June 27, 2023

@hosongn52153496 – Try the following generic script. It saves to PSD, however, it could also save to layered TIFF or flattened JPEG etc. Let me know if any changes are required for your specific use case.

 

/* 

Stack N Number of Document Sets to Layers - Top Level Folder.jsx
Stephen Marsh
8th June 2024 Version
https://community.adobe.com/t5/photoshop-ecosystem-discussions/script-to-automate-load-files-into-stack/m-p/13499068

A generic, skeleton "framework" script to help fast-track development of similar scripts for combining multiple "sequence" single-layer files to layers.

This script requires input files from a single folder to be alpha/numeric sorting in order to stack in the correct set quantity. 

Example: File-01.jpg File-02.jpg etc, FileA1.tif FileA2.tif etc, File1a.tif File1b.tif etc.

A minimum of 2 or more files per stack is required. The quantity of input files must be evenly divisible by the stack quantity.

A named action set and action can be set on line 159 to "do something" with the stacked layers.

*/

#target photoshop

// app.documents.length === 0
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 .reverse() for the first filename in the merged file
            // Remove .reverse() for the last filename in the merged file
            fileList.sort().reverse();

            //////////////////////////// Static Set Quantity - No GUI ////////////////////////////
            // var setQty = 2;
            //////////////////////////////////////////////////////////////////////////////////////

            // or...

            //////////////////////////// Variable Set Quantity - GUI /////////////////////////////
            // Loop the input prompt until a number is entered
            var origInput;
            while (isNaN(origInput = prompt('No. of files per set (minimum 2):', '2')));
            // Test if cancel returns null, then terminate the script
            if (origInput === null) {
                alert('Script cancelled!');
                return
            }
            // Test if an empty string is returned, then terminate the script 
            if (origInput === '') {
                alert('A value was not entered, script cancelled!');
                return
            }
            // Test if a value less than 2 is returned, then terminate the script 
            if (origInput < 2) {
                alert('A value less than 2 was entered, script cancelled!');
                return
            }
            // Convert decimal input to integer
            var setQty = parseInt(origInput);
            //////////////////////////////////////////////////////////////////////////////////////

            // 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();
            */
            
            // Hide the Photoshop panels
            app.togglePalettes();
            
            // Script running notification window - courtesy of William Campbell
            // https://www.marspremedia.com/download?asset=adobe-script-tutorial-11.zip
            // https://youtu.be/JXPeLi6uPv4?si=Qx0OVNLAOzDrYPB4
            var working;
            working = new Window("palette");
            working.preferredSize = [300, 80];
            working.add("statictext");
            working.t = working.add("statictext");
            working.add("statictext");
            working.display = function (message) {
                this.t.text = message || "Script running, please wait...";
                this.show();
                app.refresh();
            };
            working.display();

            // 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];

                    // Do something to the stacked active layer (blend mode, opacity etc)
                    // app.activeDocument.activeLayer.blendMode = BlendMode.MULTIPLY;

                    app.documents[1].close(SaveOptions.DONOTSAVECHANGES);
                }

                ////////////////////////////////// Start doing stuff //////////////////////////////////

                /*
                // Run an action on the stacked layers, change the case-sensitive names as required...
                try {
                    app.doAction("My Action", "My Action Set Folder");
                } catch (e) { }
                */

                /*
                // Average stacked layers
                app.runMenuItem(stringIDToTypeID("selectAllLayers"));
                var idnewPlacedLayer = stringIDToTypeID("newPlacedLayer");
                executeAction(idnewPlacedLayer, undefined, DialogModes.NO);
                var idapplyImageStackPluginRenderer = stringIDToTypeID("applyImageStackPluginRenderer");
                var desc1217 = new ActionDescriptor();
                var idimageStackPlugin = stringIDToTypeID("imageStackPlugin");
                var idavrg = charIDToTypeID("avrg");
                desc1217.putClass(idimageStackPlugin, idavrg);
                var idname = stringIDToTypeID("name");
                desc1217.putString(idname, """Mean""");
                executeAction(idapplyImageStackPluginRenderer, desc1217, DialogModes.NO);
                */

                ////////////////////////////////// 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;

            // Restore the Photoshop panels
            app.togglePalettes();

            // Ensure Photoshop has focus before closing the running script notification window
            app.bringToFront();
            working.close();

            // 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 the Photoshop panels
        app.togglePalettes();

        // Restore saved dialogs
        app.displayDialogs = restoreDialogMode;
        alert("If you see this message, something went wrong!" + "\r" + e + ' ' + e.line);
    }
}

else {
    alert('Stack "N" Number of Sets:' + '\n' + 'Please close all open documents before running this script!');
}

 

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

 

Known Participant
June 27, 2023

@Stephen Marsh 
O M G !!
It totally worked!!!
Thank you so so much!

Now, is it possible to change the final format to TIFF?

Stephen Marsh
Community Expert
Community Expert
June 27, 2023
quote

@Stephen Marsh 
O M G !!
It totally worked!!!
Thank you so so much!

Now, is it possible to change the final format to TIFF?


By @hosongn52153496

 

Certainly, however, is there anything else that needs to be changed? Layer names? Output file name? Output location? Do the stacked layers require further processing? Something else?

Stephen Marsh
Community Expert
Community Expert
June 26, 2023

This topic comes up regularly, I'll post the code later.

Sef McCullough
Community Expert
Community Expert
June 26, 2023

Re: the code - @Stephen Marsh did you write that script?

Stephen Marsh
Community Expert
Community Expert
June 27, 2023

Is there a bowing emoji? 


quote

Is there a bowing emoji? 


By @Sef McCullough

 

I'd need one for "standing on the shoulders of giants" as I certainly didn't create the script in a vacuum.

mglush
Community Expert
Community Expert
June 26, 2023

Another neat feature of using Sef's idea about "Loading files into Stacks" is that it also loads the file name as th layer name so you can see exactly which layers go toether!

Michelle

Sef McCullough
Community Expert
Community Expert
June 26, 2023

Hi @hosongn52153496 ,

Yep, I can see that would be painful. Luckily there's an easy solution:
Just go to File>Scripts>Load Files into Stack...
You can run on either files that are open in Photoshop, or files you select on your hard drive.
Give it a try and see which way you think might be the quickest for your workflow. Just click the browse button to navigate to images on your hard drive.
You might also record an action that selects File>Open so you can select 2 files, then runs the Load Files into Stack script and assign a shortcut key to it. That way you could just hit an F-Key, choose 2 files, OK, Load Open Files, and Save. Viola.
Let us know what works for you!
Thanks,

Sef

Known Participant
June 27, 2023

Thank you @Sef McCullough for the suggestion!
However, I was looking for a solution that works with several hundreds of images in a folder.
Is this method works for that?

 

Sef McCullough
Community Expert
Community Expert
June 28, 2023

No worries @hosongn52153496 - as you already know, I think @Stephen Marsh 's script solution below is the thing!