Skip to main content
EmojiStickers.com
Known Participant
June 13, 2024
Answered

Looking for a script or action to batch process 3400+ files. Need help!

  • June 13, 2024
  • 3 replies
  • 5701 views

First, I filmed a video of what I need to do on a mass scale batch process. So that's attached. I've also attached a sample PSD and PNG file. 

 

I'm the Emoji Stickers guy and I need to create a mockup of a hand holding an emoji sticker for all 3400+ emojis. 

Here's what I do manually: 

I have a PSD open. In the PSD there are three (3) layers: 1. Background (Bottom Layer), 2. Hand (Middle Layer), and 3. Thumb/Fingers (Top Layer).  (This PSD is attached)

 

With the PSD open, it would import the Emoji Sticker PNG file, place it in it's own layer above the Hand layer and below the Fingers layer, resize it to 21%, center it on the artboard, and save as PNG. 

 

After saving, it would delete that layer, and repeat with the the next PNG in that folder. 

 

Also, would be amazing to name the newly exported PNG the same name as the original PNG (emoji) that was imported. 

 

Can this be done? Free emoji stickers to anymore that can figure this out 🤙

This topic has been closed for replies.
Correct answer Stephen Marsh

@EmojiStickers.com 

 

Try this script. The template document must be open. You will be prompted to select the input folder containing the source emoji PNG files. You will be prompted to select the output folder to save the new combined PNG files to.

 

/*
Batch Emoji Mockup.jsx
v1.0 - 14th June 2024, Stephen Marsh
https://community.adobe.com/t5/photoshop-ecosystem-discussions/looking-for-a-script-or-action-to-batch-process-3400-files-need-help/td-p/14680348
*/

#target photoshop

if (app.documents.length) {

    (function () {

        try {
            // Select the source files
            /*
            var theFiles = File.openDialog('Select the file/s:', Multiselect = true);
            if (theFiles === null) {
                alert('Script cancelled!');
                return;
            }
            */
            
            // Select the input folder
            var theFiles = Folder.selectDialog("Select the folder containing the emoji PNG files:");
            if (theFiles === null) {
                alert('Script cancelled!');
                return;
            }
            var fileList = theFiles.getFiles(/\.(png)$/i);
            fileList.sort();

            // Select the output folder
            var outputFolder = Folder.selectDialog("Please select the output folder:");
            if (outputFolder === null) {
                alert('Script cancelled!');
                return;
            }

            // 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 counter
            var counter = 0;

            // Get and set the ruler units
            var origRulerUnits = app.preferences.rulerUnits;
            app.preferences.rulerUnits = Units.PIXELS;

            // Set the active doc as the template doc
            var templateDoc = app.activeDocument;
            var templateDocName = app.activeDocument.name;

            // Ensure that the Hand Bottom layer is active
            if (app.activeDocument.activeLayer.name != 'Hand Bottom') {
                app.activeDocument.activeLayer = app.activeDocument.layers.getByName('Hand Bottom');
            }

            // Remove unnecessary metadata
            removeDocumentAncestorsMetadata();
            removeCRSmetadata();
            removeXMPmetadata();

            // Loop over the files
            for (var i = 0; i < fileList.length; i++) {

                // Open each selected file
                app.open(File(fileList[i]));

                // Set the sourceDoc as the active document
                var sourceDoc = app.activeDocument;

                // Select the source layer
                app.activeDocument.activeLayer = app.activeDocument.layers[0];

                // Duplicate the source layer to the template doc
                dupeLayer(templateDocName, app.activeDocument.name.replace(/\.[^\.]+$/, ''));

                // Set the template doc as the active document
                app.activeDocument = templateDoc;

                // Centre the duped layer on the template canvas
                app.activeDocument.activeLayer.translate(app.activeDocument.width / 2 - (app.activeDocument.activeLayer.bounds[0] + app.activeDocument.activeLayer.bounds[2]) / 2,
                    app.activeDocument.height / 2 - (app.activeDocument.activeLayer.bounds[1] + app.activeDocument.activeLayer.bounds[3]) / 2);
                
                // Resize to 21% scale
                scaleLayer(21.0, 21.0);

                // Close the source doc
                sourceDoc.close(SaveOptions.DONOTSAVECHANGES);

                // File name from emoji layer name
                var docName = app.activeDocument.activeLayer.name.replace(/\.[^\.]+$/, '');

                // Save as PNG options
                var pngFile = new File(outputFolder + "/" + docName + ".png");
                var pngOptions = new PNGSaveOptions();
                pngOptions.compression = 9; // 0-9
                pngOptions.interlaced = false;
                app.activeDocument.saveAs(pngFile, pngOptions, true, Extension.LOWERCASE);

                // Delete the emoji layer
                app.activeDocument.activeLayer.remove();

                // Increment the file counter
                counter++
            }

            // Restore the original ruler units
            app.preferences.rulerUnits = origRulerUnits;

            // Close the template doc
            templateDoc.close(SaveOptions.DONOTSAVECHANGES);

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

            // End of script notification
            app.beep();
            alert('Script completed!' + '\r' + counter + ' files saved to:' + '\r' + outputFolder);

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


            // Functions

            function dupeLayer(targetDocName, sourceLayerName) {
                function s2t(s) {
                    return app.stringIDToTypeID(s);
                }
                var descriptor = new ActionDescriptor();
                var list = new ActionList();
                var reference = new ActionReference();
                var reference2 = new ActionReference();
                reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
                descriptor.putReference(s2t("null"), reference);
                reference2.putName(s2t("document"), targetDocName);
                descriptor.putReference(s2t("to"), reference2);
                descriptor.putString(s2t("name"), sourceLayerName);
                descriptor.putList(s2t("ID"), list);
                executeAction(s2t("duplicate"), descriptor, DialogModes.NO);
            }

            function scaleLayer(width, height) {
                var s2t = function (s) {
                    return app.stringIDToTypeID(s);
                };
                var descriptor = new ActionDescriptor();
                var descriptor2 = new ActionDescriptor();
                var reference = new ActionReference();
                reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
                descriptor.putReference(s2t("null"), reference);
                descriptor.putEnumerated(s2t("freeTransformCenterState"), s2t("quadCenterState"), s2t("QCSAverage"));
                descriptor2.putUnitDouble(s2t("horizontal"), s2t("pixelsUnit"), 0);
                descriptor2.putUnitDouble(s2t("vertical"), s2t("pixelsUnit"), 0);
                descriptor.putObject(s2t("offset"), s2t("offset"), descriptor2);
                descriptor.putUnitDouble(s2t("width"), s2t("percentUnit"), width);
                descriptor.putUnitDouble(s2t("height"), s2t("percentUnit"), height);
                descriptor.putEnumerated(s2t("interfaceIconFrameDimmed"), s2t("interpolationType"), s2t("bicubicSmoother"));
                executeAction(s2t("transform"), descriptor, DialogModes.NO);
            }

            function removeXMPmetadata() {
                //https://community.adobe.com/t5/photoshop/script-to-remove-all-meta-data-from-the-photo/td-p/10400906
                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 removeCRSmetadata() {
                //community.adobe.com/t5/photoshop/remove-crs-metadata/td-p/10306935
                if (!documents.length) return;
                if (ExternalObject.AdobeXMPScript === undefined) ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");
                var xmp = new XMPMeta(app.activeDocument.xmpMetadata.rawData);
                XMPUtils.removeProperties(xmp, XMPConst.NS_CAMERA_RAW, "", XMPConst.REMOVE_ALL_PROPERTIES);
                app.activeDocument.xmpMetadata.rawData = xmp.serialize();
            }

            function removeDocumentAncestorsMetadata() {
                whatApp = String(app.name); //String version of the app name
                if (whatApp.search("Photoshop") > 0) { //Check for photoshop specifically, or this will cause errors
                    if (ExternalObject.AdobeXMPScript === undefined) ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");
                    var xmp = new XMPMeta(activeDocument.xmpMetadata.rawData);
                    // Begone foul Document Ancestors!
                    xmp.deleteProperty(XMPConst.NS_PHOTOSHOP, "DocumentAncestors");
                    app.activeDocument.xmpMetadata.rawData = xmp.serialize();
                }
            }

        } catch (e) {
            alert('Error!' + '\r' + e + ', Line: ' + e.line);
        }

    })();

} else {
    alert('A document must be open to run this script!');
}

 

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

3 replies

Stephen Marsh
Stephen MarshCorrect answer
Community Expert
June 13, 2024

@EmojiStickers.com 

 

Try this script. The template document must be open. You will be prompted to select the input folder containing the source emoji PNG files. You will be prompted to select the output folder to save the new combined PNG files to.

 

/*
Batch Emoji Mockup.jsx
v1.0 - 14th June 2024, Stephen Marsh
https://community.adobe.com/t5/photoshop-ecosystem-discussions/looking-for-a-script-or-action-to-batch-process-3400-files-need-help/td-p/14680348
*/

#target photoshop

if (app.documents.length) {

    (function () {

        try {
            // Select the source files
            /*
            var theFiles = File.openDialog('Select the file/s:', Multiselect = true);
            if (theFiles === null) {
                alert('Script cancelled!');
                return;
            }
            */
            
            // Select the input folder
            var theFiles = Folder.selectDialog("Select the folder containing the emoji PNG files:");
            if (theFiles === null) {
                alert('Script cancelled!');
                return;
            }
            var fileList = theFiles.getFiles(/\.(png)$/i);
            fileList.sort();

            // Select the output folder
            var outputFolder = Folder.selectDialog("Please select the output folder:");
            if (outputFolder === null) {
                alert('Script cancelled!');
                return;
            }

            // 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 counter
            var counter = 0;

            // Get and set the ruler units
            var origRulerUnits = app.preferences.rulerUnits;
            app.preferences.rulerUnits = Units.PIXELS;

            // Set the active doc as the template doc
            var templateDoc = app.activeDocument;
            var templateDocName = app.activeDocument.name;

            // Ensure that the Hand Bottom layer is active
            if (app.activeDocument.activeLayer.name != 'Hand Bottom') {
                app.activeDocument.activeLayer = app.activeDocument.layers.getByName('Hand Bottom');
            }

            // Remove unnecessary metadata
            removeDocumentAncestorsMetadata();
            removeCRSmetadata();
            removeXMPmetadata();

            // Loop over the files
            for (var i = 0; i < fileList.length; i++) {

                // Open each selected file
                app.open(File(fileList[i]));

                // Set the sourceDoc as the active document
                var sourceDoc = app.activeDocument;

                // Select the source layer
                app.activeDocument.activeLayer = app.activeDocument.layers[0];

                // Duplicate the source layer to the template doc
                dupeLayer(templateDocName, app.activeDocument.name.replace(/\.[^\.]+$/, ''));

                // Set the template doc as the active document
                app.activeDocument = templateDoc;

                // Centre the duped layer on the template canvas
                app.activeDocument.activeLayer.translate(app.activeDocument.width / 2 - (app.activeDocument.activeLayer.bounds[0] + app.activeDocument.activeLayer.bounds[2]) / 2,
                    app.activeDocument.height / 2 - (app.activeDocument.activeLayer.bounds[1] + app.activeDocument.activeLayer.bounds[3]) / 2);
                
                // Resize to 21% scale
                scaleLayer(21.0, 21.0);

                // Close the source doc
                sourceDoc.close(SaveOptions.DONOTSAVECHANGES);

                // File name from emoji layer name
                var docName = app.activeDocument.activeLayer.name.replace(/\.[^\.]+$/, '');

                // Save as PNG options
                var pngFile = new File(outputFolder + "/" + docName + ".png");
                var pngOptions = new PNGSaveOptions();
                pngOptions.compression = 9; // 0-9
                pngOptions.interlaced = false;
                app.activeDocument.saveAs(pngFile, pngOptions, true, Extension.LOWERCASE);

                // Delete the emoji layer
                app.activeDocument.activeLayer.remove();

                // Increment the file counter
                counter++
            }

            // Restore the original ruler units
            app.preferences.rulerUnits = origRulerUnits;

            // Close the template doc
            templateDoc.close(SaveOptions.DONOTSAVECHANGES);

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

            // End of script notification
            app.beep();
            alert('Script completed!' + '\r' + counter + ' files saved to:' + '\r' + outputFolder);

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


            // Functions

            function dupeLayer(targetDocName, sourceLayerName) {
                function s2t(s) {
                    return app.stringIDToTypeID(s);
                }
                var descriptor = new ActionDescriptor();
                var list = new ActionList();
                var reference = new ActionReference();
                var reference2 = new ActionReference();
                reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
                descriptor.putReference(s2t("null"), reference);
                reference2.putName(s2t("document"), targetDocName);
                descriptor.putReference(s2t("to"), reference2);
                descriptor.putString(s2t("name"), sourceLayerName);
                descriptor.putList(s2t("ID"), list);
                executeAction(s2t("duplicate"), descriptor, DialogModes.NO);
            }

            function scaleLayer(width, height) {
                var s2t = function (s) {
                    return app.stringIDToTypeID(s);
                };
                var descriptor = new ActionDescriptor();
                var descriptor2 = new ActionDescriptor();
                var reference = new ActionReference();
                reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
                descriptor.putReference(s2t("null"), reference);
                descriptor.putEnumerated(s2t("freeTransformCenterState"), s2t("quadCenterState"), s2t("QCSAverage"));
                descriptor2.putUnitDouble(s2t("horizontal"), s2t("pixelsUnit"), 0);
                descriptor2.putUnitDouble(s2t("vertical"), s2t("pixelsUnit"), 0);
                descriptor.putObject(s2t("offset"), s2t("offset"), descriptor2);
                descriptor.putUnitDouble(s2t("width"), s2t("percentUnit"), width);
                descriptor.putUnitDouble(s2t("height"), s2t("percentUnit"), height);
                descriptor.putEnumerated(s2t("interfaceIconFrameDimmed"), s2t("interpolationType"), s2t("bicubicSmoother"));
                executeAction(s2t("transform"), descriptor, DialogModes.NO);
            }

            function removeXMPmetadata() {
                //https://community.adobe.com/t5/photoshop/script-to-remove-all-meta-data-from-the-photo/td-p/10400906
                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 removeCRSmetadata() {
                //community.adobe.com/t5/photoshop/remove-crs-metadata/td-p/10306935
                if (!documents.length) return;
                if (ExternalObject.AdobeXMPScript === undefined) ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");
                var xmp = new XMPMeta(app.activeDocument.xmpMetadata.rawData);
                XMPUtils.removeProperties(xmp, XMPConst.NS_CAMERA_RAW, "", XMPConst.REMOVE_ALL_PROPERTIES);
                app.activeDocument.xmpMetadata.rawData = xmp.serialize();
            }

            function removeDocumentAncestorsMetadata() {
                whatApp = String(app.name); //String version of the app name
                if (whatApp.search("Photoshop") > 0) { //Check for photoshop specifically, or this will cause errors
                    if (ExternalObject.AdobeXMPScript === undefined) ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");
                    var xmp = new XMPMeta(activeDocument.xmpMetadata.rawData);
                    // Begone foul Document Ancestors!
                    xmp.deleteProperty(XMPConst.NS_PHOTOSHOP, "DocumentAncestors");
                    app.activeDocument.xmpMetadata.rawData = xmp.serialize();
                }
            }

        } catch (e) {
            alert('Error!' + '\r' + e + ', Line: ' + e.line);
        }

    })();

} else {
    alert('A document must be open to run this script!');
}

 

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

Known Participant
June 13, 2024
Uses ExtendScript not AppleScript but you can convert it if need be. Just replace the path to your folder.


//Global Variables
var pngFolder = "C:/PathToYourPngFolder"
var doc = app.activeDocument

//Script
main();

//Functions
   
// Function to place and resize PNGs
function placeAndResizePNG(filePath, handLayer, fingersLayer, doc) {
    var pngFile = new File(filePath);
   
    activeDocument.activeLayer = doc.artLayers.getByName(handLayer);
    // Place PNG file
    app.open(pngFile);
    app.activeDocument.activeLayer.duplicate(doc);
    app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
    var placedLayer = doc.activeLayer;

    // Move the layer to the above the hand layer
    placedLayer.move(doc.artLayers.getByName(handLayer), ElementPlacement.PLACEBEFORE);
    // Resize to 21%
    var bounds = placedLayer.bounds;
    var width = bounds[2] - bounds[0];
    var height = bounds[3] - bounds[1];
    var resizePercentage = 21;
    placedLayer.resize(resizePercentage, resizePercentage, AnchorPosition.MIDDLECENTER);

    // Center the layer
    placedLayer.translate(-(placedLayer.bounds[0] + placedLayer.bounds[2]) / 2 + doc.width / 2,
                          -(placedLayer.bounds[1] + placedLayer.bounds[3]) / 2 + doc.height / 2);

    //Save the file into a new folder nested in the original folder
    var saveFolder = new Folder(pngFolder + "/Resized");
    if (!saveFolder.exists) {
        saveFolder.create();
    }
    var saveFile = new File(saveFolder + "/" + pngFile.name);
    var pngSaveOptions = new PNGSaveOptions();
    pngSaveOptions.compression = 9;
    doc.saveAs(saveFile, pngSaveOptions, true, Extension.LOWERCASE);
   
    // Delete the imported layer
    placedLayer.remove();
}

// Main function
function main() {
var doc = app.activeDocument;

    var handLayerName = "Hand Bottom"; // Update with your hand layer name
    var fingersLayerName = "Hand Top"; // Update with your fingers layer name

    var pngFiles = Folder(pngFolder).getFiles("*.png");

    for (var i = 0; i < pngFiles.length; i++) {
        placeAndResizePNG(pngFiles[i].fsName, handLayerName, fingersLayerName, doc);
    }
    doc.close(SaveOptions.DONOTSAVECHANGES);
}
Stephen Marsh
Community Expert
June 13, 2024

This could be done via an Action and the Batch command, including the correct naming (it just has to be setup opposite to most people's expectations) – however, a Script would be better.

EmojiStickers.com
Known Participant
June 13, 2024

Do you have a script?

 

Stephen Marsh
Community Expert
June 13, 2024
quote

Do you have a script?

 


By @EmojiStickers.com


It would need to be written for your specific work, this isn't generic.

 

Where is the PNG saved? Next to the PSD or elsewhere?

 

The uploaded PSD has 4 layers, there is a "Layer 1" with content moved outside of the canvas. Is this an error, you mentioned only 3 layers?