Skip to main content
Known Participant
June 28, 2023
Question

Is it possible to batch two images onto a single background?

  • June 28, 2023
  • 4 replies
  • 1230 views

Hi! I currently have an action in my photoshop program which allows me to batch an entire folder of images onto the same background image so that they all have the same border. I would like to do this for TWO images at a time, if it is possible. Essentially I would need PS to recognize two images at a time being brought in, placed over the background image, and then save. Then, bring in the next two photos, do the same thing, and so on until the folder is finished. I appreciate any help with this! Thanks!!

This topic has been closed for replies.

4 replies

Stephen Marsh
Community Expert
Community Expert
July 2, 2023

@Brian22351872dw34 - So where are you at with this?

Known Participant
July 6, 2023

Wow thank you so much for the help, I will be reaching out further, this definitely clears things up that it seems to be at least possible, I am just very novice so I will need professional help with this. Thank you again!

Stephen Marsh
Community Expert
Community Expert
July 6, 2023

@Brian22351872dw34 – Thank you for the requested samples sent via PM. Based on what I have seen, I'm going to suggest using the BatchMultiImageCollage.jsx script from the late JJMack's Photo Collage Toolkit set:

 

https://github.com/MarshySwamp/JJMack-Archive

PhotoCollageToolkit.zip

https://github.com/MarshySwamp/JJMack-Archive/blob/main/README.md

 

I have attached a sample PSD template showing the alpha channel names/positions required by the script and the background layer with image mask from both alpha channels stacked over the top of the required Background layer

Stephen Marsh
Community Expert
Community Expert
June 28, 2023

The following script assumes that each image pair is the same width and will stack them side by side and save as a layered PSD.

 

Change the action set and action name on line 147 to run an action on the layered file, or simply remove the line if you don't wish to run an action:

 

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

 

The full script code below:

 

/* 

https://community.adobe.com/t5/photoshop-ecosystem-discussions/is-it-possible-to-batch-two-images-onto-a-single-background/td-p/13899610
Stack 2 Documents Side by Side as Layers.jsx
Stephen Marsh
29th June 2023

Based on 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.

*/

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

            // 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 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 desc341 = new ActionDescriptor();
                var idwidth = stringIDToTypeID("width");
                var idpercentUnit = stringIDToTypeID("percentUnit");
                desc341.putUnitDouble(idwidth, idpercentUnit, 200.000000);
                var idheight = stringIDToTypeID("height");
                var idpercentUnit = stringIDToTypeID("percentUnit");
                desc341.putUnitDouble(idheight, idpercentUnit, 100.000000);
                var idhorizontal = stringIDToTypeID("horizontal");
                var idhorizontalLocation = stringIDToTypeID("horizontalLocation");
                var idleft = stringIDToTypeID("left");
                desc341.putEnumerated(idhorizontal, idhorizontalLocation, idleft);
                var idvertical = stringIDToTypeID("vertical");
                var idverticalLocation = stringIDToTypeID("verticalLocation");
                var idcenter = stringIDToTypeID("center");
                desc341.putEnumerated(idvertical, idverticalLocation, idcenter);
                executeAction(idcanvasSize, desc341, DialogModes.NO);

                var idset = stringIDToTypeID("set");
                var desc347 = new ActionDescriptor();
                var idnull = stringIDToTypeID("null");
                var ref48 = new ActionReference();
                var idchannel = stringIDToTypeID("channel");
                var idselection = stringIDToTypeID("selection");
                ref48.putProperty(idchannel, idselection);
                desc347.putReference(idnull, ref48);
                var idto = stringIDToTypeID("to");
                var idordinal = stringIDToTypeID("ordinal");
                var idallEnum = stringIDToTypeID("allEnum");
                desc347.putEnumerated(idto, idordinal, idallEnum);
                executeAction(idset, desc347, DialogModes.NO);

                var idalign = stringIDToTypeID("align");
                var desc350 = new ActionDescriptor();
                var idnull = stringIDToTypeID("null");
                var ref50 = new ActionReference();
                var idlayer = stringIDToTypeID("layer");
                var idordinal = stringIDToTypeID("ordinal");
                var idtargetEnum = stringIDToTypeID("targetEnum");
                ref50.putEnumerated(idlayer, idordinal, idtargetEnum);
                desc350.putReference(idnull, ref50);
                var idusing = stringIDToTypeID("using");
                var idalignDistributeSelector = stringIDToTypeID("alignDistributeSelector");
                var idADSRights = stringIDToTypeID("ADSRights");
                desc350.putEnumerated(idusing, idalignDistributeSelector, idADSRights);
                var idalignToCanvas = stringIDToTypeID("alignToCanvas");
                desc350.putBoolean(idalignToCanvas, false);
                executeAction(idalign, desc350, DialogModes.NO);

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

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

Sef McCullough
Community Expert
Community Expert
June 28, 2023

Hi @Brian22351872dw34 

The in-Photoshop solution that seems doable is to use File>Automate>Contact Sheet II. This allows you to create individual PS docs populated with images from a folder you choose. To place them side by side, set the the thumbnails to 2x1 and adjust any of the other settings to your taste.
At this stage you've got files with your images placed two at a time. From here you'll have to see if you can use or tweak your existing actions to place those resulting files into the background image.
It's a little clunky, but seems like a good option.
Beyond this, I think you'd need to script something, and I'd leave that answer up to someone smarter than me like @Stephen Marsh 🙂
Let us know how it goes!
Sef

 

Known Participant
June 28, 2023

Wow, thank you so much Sef!! I am no expert, and I usually hire a tutor to help me with this, but I will do my best to follow your steps on my own for now. Thank you so much!!!

Known Participant
June 28, 2023

Also, I should clarify, both images will need to be positioned on the background at a specific location on the background, specifically side by side. Thanks

Stephen Marsh
Community Expert
Community Expert
June 28, 2023

@Brian22351872dw34 - I can help you automate this. If it is just a case of having two images side by side in a batch and then your action will do everything else, then that is easiest... But even then, are both images per file the same size or is one different to the other?

 

Otherwise, the devil is in the details.

 

It would be helpful if you could provide the working files:

 

* Common background image

 

* Sample of one set of 2 images

 

* Sample of a set of another 2 images that may have different sizes or ratio

 

* Sample of the finished 2up result

 

What file format and options should this save to?