Welcome Dialog

Welcome to the Community!

We have a brand new look! Take a tour with us and explore the latest updates on Adobe Support Community.


Batch Processing: Load 2 files as layers, play action, export image, repeat for every "file pair"

Community Beginner ,
Aug 14, 2021 Aug 14, 2021

Copy link to clipboard

Copied

I have a workflow that I want to convert to a batch process. These are the steps:

  1. Open two files in photoshop as layers i.e. file1_layer1.tiff and file1_layer2.tiff
  2. Play action (select subject in layer2, expand and feather mask, create a mask on layer2 with selection)
  3. Export image as JPEG
  4. Repeat steps 1-3 with next "file pair" in the same directory i.e. file2_layer1.tiff and file2_layer2.tiff
  5. Do step 4 until all "file pairs" in the directory have been processed.

 

Here is an example of my windows file system diectory:

fileListing.jpg

Any help with this would be greatly appreciated!

TOPICS
Actions and scripting, Windows

Views

96

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Adobe Community Professional , Aug 14, 2021 Aug 14, 2021
@garygerber  The following script will get you most of the way there. It currently saves in PSD. The image naming may also need tweaking. I don't have time now to make the tweaks, but as the script is 99% there anyway, it will not take too long to fine tune. I'll come back to you, however do you want save as JPEG or Export Save for Web and what options? /* Stack N Number of Docs to Layers.jsx Stephen Marsh 20th August 2021 Version A generic, skeleton "framework" script to help fast-trac...

Likes

Translate

Translate
Adobe Community Professional ,
Aug 14, 2021 Aug 14, 2021

Copy link to clipboard

Copied

@garygerber 

 

The following script will get you most of the way there. It currently saves in PSD. The image naming may also need tweaking. I don't have time now to make the tweaks, but as the script is 99% there anyway, it will not take too long to fine tune. I'll come back to you, however do you want save as JPEG or Export Save for Web and what options?

 

 

/* 

Stack N Number of Docs to Layers.jsx
Stephen Marsh
20th August 2021 Version

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 135 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();
            */

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

                // app.doAction("My Action", "My Action Set Folder");

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

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

            // Ensure that the following file format filter matches the save format
            // .getFiles(/\.(tif|tiff)$/i);
            var outputList = outputFolder.getFiles(/\.(psd)$/i);
            // var outputList = outputFolder.getFiles(/\.(jpg|jpeg)$/i);
            alert('Script completed!' + '\n' + outputList.length + ' 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!");

    }
}

else {

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

}

 

 

EDIT: Original script updated 20th August 2021

 

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Aug 14, 2021 Aug 14, 2021

Copy link to clipboard

Copied

Wow @Stephen_A_Marsh !!! That worked so great!

I did change the saved output to jpeg and it worked perfectly! 

 

jpgSaveOptions = new JPEGSaveOptions();
jpgSaveOptions.embedColorProfile = true;
jpgSaveOptions.formatOptions = FormatOptions.STANDARDBASELINE;
jpgSaveOptions.matte = MatteType.NONE;
jpgSaveOptions.quality = 8;
app.activeDocument.saveAs(saveFile, jpgSaveOptions, true, Extension.LOWERCASE);

 

You just saved me a ton of time! Thank you soooo much!

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe Community Professional ,
Aug 14, 2021 Aug 14, 2021

Copy link to clipboard

Copied

LATEST

@garygerber 

 

Sorry, I didn't see this reply when I posted the updated script. I'm glad you got there!

 

This type of question comes up so frequently, that I wanted to be able to create a basic skeleton/framework script that could be easily adapted for each specific request.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe Community Professional ,
Aug 14, 2021 Aug 14, 2021

Copy link to clipboard

Copied

Photoshop Scripting will be required for automating a Photoshop process like you describe.  Action can not hack a process that required  logic  to get file lists of image files in folders match pairs of files open pen pair and handles problems that may arise. Actions are a sequence of recorded Photoshop steps with recorded step settings.  Photoshop Batch can open image files in a folder, play an action and save an output file. One image file at a time.  Batch can not open pairs of files.

JJMack

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Aug 14, 2021 Aug 14, 2021

Copy link to clipboard

Copied

Thanks @JJMack

 

@Stephen_A_Marshcame in with a perfect script. 

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe Community Professional ,
Aug 14, 2021 Aug 14, 2021

Copy link to clipboard

Copied

@garygerber 

 

As promised, I have now had time to complete the previous generic script into what you require.

 

This script will save as JPEG to quality level 10, you can easily change this in the code. It will also name the output directory as you require. The only thing you need to do is to change the action set and action name to match your naming (line 115: "My Action", "My Action Set Folder").

 

/* 
Batch Processing: Load 2 files as layers, play action, export image, repeat for every "file pair"
https://community.adobe.com/t5/photoshop-ecosystem/batch-processing-load-2-files-as-layers-play-action-export-image-repeat-for-every-quot-file-pair/m-p/12317165#M573845

Stephen Marsh - 2021

Notes:
Stacks alpha-numeric sorting input files into pairs, runs an action, save as JPEG quality level 10
Change line 115 to reference your action set and action:
app.doAction("My Action", "My Action Set Folder");
*/


#target photoshop


if (app.documents.length === 0) {

    try {

        // Save and disable dialogs
        var restoreDialogMode = app.displayDialogs;
        app.displayDialogs = DialogModes.NO;


        // Call the main script function
        batchSetProcessing();

        // Main script function
        function batchSetProcessing() {


            // Select the input folder
            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;

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


            // 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 + '/ExportedJPEGs'));
            if (!outputFolder.exists) outputFolder.create();


            // 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) { }
                }

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

                // 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 active layer (blend mode, opacity etc)
                    // app.activeDocument.activeLayer.blendMode = BlendMode.MULTIPLY;

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


                function docNameToLayerName() {
                    var layerName = app.activeDocument.name.replace(/\.[^\.]+$/, '');
                    app.activeDocument.activeLayer.name = layerName;
                }


                // Do something with the layer stack, either script or action based...
                app.doAction("My Action", "My Action Set Folder");
                // app.activeDocument.flatten();

                ////////////////////////////////// Finish doing stuff //////////////////////////////////

                // https://prepression.blogspot.com/2017/06/metadata-bloat-photoshopdocumentancestors.html
                deleteDocumentAncestorsMetadata();

                function deleteDocumentAncestorsMetadata() {
                    // https://forums.adobe.com/message/8456985#8456985
                    if (ExternalObject.AdobeXMPScript === undefined) ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");
                    var xmp = new XMPMeta(activeDocument.xmpMetadata.rawData);
                    xmp.deleteProperty(XMPConst.NS_PHOTOSHOP, "DocumentAncestors");
                    app.activeDocument.xmpMetadata.rawData = xmp.serialize();
                }

                // Save name + suffix & save path
                var Name = app.activeDocument.name.replace(/\.[^\.]+$/, '');
                var saveFile = File(outputFolder + '/' + Name + '_x' + setQty + '-Sets' + '.jpg');


                // Call the JPEG save function
                saveJPEG(saveFile);

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

                }

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

            }


            // Restore saved dialogs
            app.displayDialogs = restoreDialogMode;

            // End of script notification
            // Ensure that the following file format filter matches the save format
            var outputList = outputFolder.getFiles(/\.(jpg|jpeg)$/i);
            alert('Script completed!' + '\n' + outputList.length + ' combined files saved to:' + '\n' + outputFolder.fsName);


            // Open the output folder
            outputFolder.execute();


        }

    } catch (e) {

        // Restore saved dialogs
        app.displayDialogs = restoreDialogMode;
        alert("If you see this message, something went unexpectedly wrong!");

    }
}

else {

    alert('Stack Into Sets of 2:' + '\n' + 'Please close all open documents before running this script!');

}

 

Downloading and Installing Adobe Scripts

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines