Skip to main content
SarahFaithMorris1600
Known Participant
January 30, 2014
Answered

Batch replace smart objects

  • January 30, 2014
  • 8 replies
  • 37837 views

Hello,

I have very minimal scripting knowledge, and every script I've found for this workflow is partial or results in "undefined".  I am on a mac running Photoshop CC (latest update).

This is what I have:

  • a mockup file of a book with the cover image set as a transformed smart object
  • a folder of images resized to fit said smart object

This is what I would like a script to do (if possible):

  • for every image in said folder
  • replace smart object with images
  • save each new mockup (one for each new image) as a PSD file.

We have to create over 40 book, CD, DVD, and Blu-Ray mockups for each flyer we do.  Smart Objects help streamline it a little but I'm just going through and using an action right now, which I know is less than ideal.  I don't mind if the file names aren't what I need them to be, so incremental file naming would be fine because I could rename them all later.

Any suggestions on how I could streamline this process without having to manually replace and save?

This topic has been closed for replies.
Correct answer c.pfaffenbichler

I tried pasting it there and it stops after it replaces the smart object and does not even go on to the saving, unfortunately.  Here's the script below:

/ replace smart object’s content and save psd;

// 2011, use it at your own risk;

#target photoshop

if (app.documents.length > 0) {

var myDocument = app.activeDocument;

var theName= myDocument.name.match(/(.*)\.[^\.]+$/)[1];

var thePath = myDocument.path;

var theLayer = myDocument.activeLayer;

// psd options;

psdOpts = new PhotoshopSaveOptions();

psdOpts.embedColorProfile = true;

psdOpts.alphaChannels = true;

psdOpts.layers = true;

psdOpts.spotColors = true;

// check if layer is smart object;

if (theLayer.kind != "LayerKind.SMARTOBJECT") {alert ("selected layer is not a smart object")}

else {

   

// select files;

if ($.os.search(/windows/i) != -1) {var theFiles = File.openDialog ("please select files", "*.png;*.jpg;*.psd;*.tif", true)}

else {var theFiles = File.openDialog ("please select files", getFiles, true)};

if (theFiles) {

   

// work through the array;

          for (var m = 0; m < theFiles.length; m++) {

             

// replace smart object;

                    theLayer = replaceContents (theFiles);

                    var theNewName = theFiles.name.match(/(.*)\.[^\.]+$/)[1];

                   

//Raise color picker for Back cover                   

                        try {

    app.activeDocument.activeLayer = app.activeDocument.layers[app.activeDocument.layers.length - 1];

    //

    var ref = new ActionReference();

    ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );

    var layerDesc = executeActionGet(ref);

    var adjList = layerDesc.getList(stringIDToTypeID('adjustment'));

    var theColors = adjList.getObjectValue(0).getObjectValue(stringIDToTypeID('color'));

    var theRed = theColors.getUnitDoubleValue(theColors.getKey(0));

    var theGreen = theColors.getUnitDoubleValue(theColors.getKey(1));

    var theBlue = theColors.getUnitDoubleValue(theColors.getKey(2));

    // =======================================================

    var idsetd = charIDToTypeID( "setd" );

        var desc7 = new ActionDescriptor();

        var idnull = charIDToTypeID( "null" );

            var ref2 = new ActionReference();

            var idcontentLayer = stringIDToTypeID( "contentLayer" );

            var idOrdn = charIDToTypeID( "Ordn" );

            var idTrgt = charIDToTypeID( "Trgt" );

            ref2.putEnumerated( idcontentLayer, idOrdn, idTrgt );

        desc7.putReference( idnull, ref2 );

        var idT = charIDToTypeID( "T   " );

            var desc8 = new ActionDescriptor();

            var idClr = charIDToTypeID( "Clr " );

        var idsolidColorLayer = stringIDToTypeID( "solidColorLayer" );

        desc7.putObject( idT, idsolidColorLayer, desc8 );

    executeAction( idsetd, desc7, DialogModes.ALL );

    } catch (e) {};

//save PSD;

                    myDocument.saveAs((new File(thePath+"/"+theName+"_"+theNewName+".psd")),psdOpts,true);

                    }

          }

}

};

////// get psds, tifs and jpgs from files //////

function getFiles (theFile) {

     if (theFile.name.match(/\.(psd|tif|jpg)$/i) != null || theFile.constructor.name == "Folder") {

          return true

          };

     };

////// replace contents //////

function replaceContents (newFile) {

// =======================================================

var idplacedLayerReplaceContents = stringIDToTypeID( "placedLayerReplaceContents" );

    var desc3 = new ActionDescriptor();

    var idnull = charIDToTypeID( "null" );

    desc3.putPath( idnull, new File( newFile ) );

    var idPgNm = charIDToTypeID( "PgNm" );

    desc3.putInteger( idPgNm, 1 );

executeAction( idplacedLayerReplaceContents, desc3, DialogModes.NO );

return app.activeDocument.activeLayer

};

Sorry, I wish I was a scripter so I could troubleshoot myself!  I am in the process of teaching myself, however.

Thanks for your time!


Please try this:

// replace smart object’s content and save psd;

// 2011, use it at your own risk;

#target photoshop

if (app.documents.length > 0) {

var myDocument = app.activeDocument;

var theName= myDocument.name.match(/(.*)\.[^\.]+$/)[1];

var thePath = myDocument.path;

var theLayer = myDocument.activeLayer;

// psd options;

psdOpts = new PhotoshopSaveOptions();

psdOpts.embedColorProfile = true;

psdOpts.alphaChannels = true;

psdOpts.layers = true;

psdOpts.spotColors = true;

// check if layer is smart object;

if (theLayer.kind != "LayerKind.SMARTOBJECT") {alert ("selected layer is not a smart object")}

else {

// select files;

if ($.os.search(/windows/i) != -1) {var theFiles = File.openDialog ("please select files", "*.psd;*.tif", true)}

else {var theFiles = File.openDialog ("please select files", getFiles, true)};

if (theFiles) {

// work through the array;

          for (var m = 0; m < theFiles.length; m++) {

// replace smart object;

                    theLayer = replaceContents (theFiles, theLayer);

                    var theNewName = theFiles.name.match(/(.*)\.[^\.]+$/)[1];

//Raise color picker for Back cover;

try {

app.activeDocument.activeLayer = app.activeDocument.layers[app.activeDocument.layers.length - 1];

// =======================================================

var idsetd = charIDToTypeID( "setd" );

var desc7 = new ActionDescriptor();

var idnull = charIDToTypeID( "null" );

var ref2 = new ActionReference();

var idcontentLayer = stringIDToTypeID( "contentLayer" );

var idOrdn = charIDToTypeID( "Ordn" );

var idTrgt = charIDToTypeID( "Trgt" );

ref2.putEnumerated( idcontentLayer, idOrdn, idTrgt );

desc7.putReference( idnull, ref2 );

var idT = charIDToTypeID( "T   " );

var desc8 = new ActionDescriptor();

var idClr = charIDToTypeID( "Clr " );

var idsolidColorLayer = stringIDToTypeID( "solidColorLayer" );

desc7.putObject( idT, idsolidColorLayer, desc8 );

executeAction( idsetd, desc7, DialogModes.ALL );

} catch (e) {};

//save jpg;

                    myDocument.saveAs((new File(thePath+"/"+theName+"_"+theNewName+".psd")),psdOpts,true);

                    }

          }

}

};

////// get psds, tifs and jpgs from files //////

function getFiles (theFile) {

     if (theFile.name.match(/\.(psd|tif)$/i) != null || theFile.constructor.name == "Folder") {

          return true

          };

     };

////// replace contents //////

function replaceContents (newFile, theSO) {

app.activeDocument.activeLayer = theSO;

// =======================================================

var idplacedLayerReplaceContents = stringIDToTypeID( "placedLayerReplaceContents" );

    var desc3 = new ActionDescriptor();

    var idnull = charIDToTypeID( "null" );

    desc3.putPath( idnull, new File( newFile ) );

    var idPgNm = charIDToTypeID( "PgNm" );

    desc3.putInteger( idPgNm, 1 );

executeAction( idplacedLayerReplaceContents, desc3, DialogModes.NO );

return app.activeDocument.activeLayer

};

8 replies

Known Participant
October 20, 2023

I would point out that if you don't want to go the .jsx Photoshop scripting route to solve this problem, there is a simple Photoshop plugin that automates this exact process for you: the Batch-Replace Smart Objects plugin.

 

It does basically exactly what the original poster was asking: Automates the creation of mockup images using all of the images from your input folder. It takes about 10 seconds to set up an automated operation: 

 

1) Select the Photoshop document to use (ie, your mockup template, which contains the Smart Object);
2) Select the input folder (which contains your artwork/design images);
3) Select the output folder (which your final images get saved to);

 

Then that's it basically. Click "Run This Now", and it'll create all of the mockup images for you.

 

 

Then in the OP's case, if he needs to use several different mockup templates in sequence (like if you're using the same artwork design, but you need to use it to generate mockups of book covers, magazine covers, wall posters, etc), you can set up multiple-step operations that will run from start to finish as well. This would also work if you're using it to create product images, where you need several product images for each artwork design you have in your input folder. Just set up the multiple-step sequence, click "Run", and it'll create all the needed mockup images for you. See this YouTube demo where the plugin is used to create 900 total mockup images, using 9 different mockup templates, with one button click.

 

A few more points on the .jsx scripting approach: I've used this method to automate the creation of tons of mockup images, and in my case, it was absolutely vital to do a few additional things: 1) Set your History States preference in Photoshop to 0 or 1. Without this, my RAM usage would climb so high, during large batch operations, that Photoshop / my computer would often crash; 2) Include a "purge all caches" operation during each loop iteration, to also help keep your Photoshop performance maximized during high-volume operations; 3) Resize your Photoshop mockup templates to the desired final aspect ratio. This can dramatically improve the speed of the automated operation, and therefore increase your throughput + ability to produce more mockup images, per unit time. Mockup templates downloaded from sites like Creative Market or the Etsy Marketplace often are sized way, way larger than you practically need for your final images. If you automate the creation of mockup images using the original aspect ratio, it'll take WAY longer than it needs to. (This same piece of advice would apply if you're automating this process using that Photoshop plugin, as well.)

Stephen Marsh
Community Expert
Community Expert
October 20, 2023

@the_king_of_goats 

 

Looking at your profile, I can see that you have posted this many times to related topic threads.

 

Commercial disclosure should be stated upfront... What is your connection/relationship to this plugin?

 

Known Participant
March 11, 2018

This is brilliant, saving me so much time!

I have a couple of questions.

1. Do you have a donation PayPal account? I would have gladly paid for this!

2. Is there a way of closing the image layers in the smart object once they are saved as jpg?

Its probably a limitation of my system but it gets to 50 images real fast and then really slows up. I'm guessing its all the open layers in the smart object? The images being pasted into the smart object are all around 15mb per file.

Many thanks

Kukurykus
Legend
March 11, 2018

I think you should make dotation for c.pfaffenbichler who made it works, not to SarahFaithMorris1600 who asked question.

Known Participant
March 11, 2018

I thought I’d quoted him, I must have missed It.

Participating Frequently
August 27, 2017

Hi  all,

I have working script which replaces smart objects with the new image, and it is working as expected.

function someFunction(){

     //some code

     changeSOContent();

}

function changeSOContent(){

     var myDocument = currentDocument;

     // some code

     var imageGroup = myDocument.layerSets.getByName('images-group');

     var imageSmartObj = imageGroup.artLayers.getByName('image-so');

     var imageFiles = Folder(imgDirPath).getFiles(/\.(jpg|psd|png)$/i);

     for (var i = 0; i < imageFiles.length; i++) {

          imageSmartObj = replaceContents(imageFiles, imageSmartObj);

          myDocument.saveAs((new File(destinationFolder + "/" + theName + ".jpg")), jpgopts, true);

     }

}

function replaceContents(newFile, theSO) {

     app.activeDocument.activeLayer = theSO;

     var idplacedLayerReplaceContents = stringIDToTypeID("placedLayerReplaceContents");

     var desc3 = new ActionDescriptor();

     var idnull = charIDToTypeID("null");

     desc3.putPath(idnull, new File(newFile));

     var idPgNm = charIDToTypeID("PgNm");

     desc3.putInteger(idPgNm, 1);

     executeAction(idplacedLayerReplaceContents, desc3, DialogModes.NO);

     return app.activeDocument.activeLayer;

}

But I want to add progress bar while script is doing the job. So I try like this

function someFunction(){

     app.doForcedProgress("Progress bar start.", "changeSOContent()");

}

function changeSOContent(){

     var myDocument = currentDocument;

     //some code

    

     var imageGroup = myDocument.layerSets.getByName('images-group');

     var imageSmartObj = imageGroup.artLayers.getByName('image-so');

     for (var i = 0; i < imageFiles.length; i++) {

         

          var canContinue = app.doProgressSubTask(i, imageFiles.length, "updateProgress()");

          if (!canContinue) return;

         

          function updateProgress(){

               app.changeProgressText("Current image: " + i + "");

          }

     

          imageSmartObj = replaceContents(imageFiles, imageSmartObj);

          myDocument.saveAs((new File(destinationFolder + "/" + theName + ".jpg")), jpgopts, true);

     }

}

function replaceContents(newFile, theSO) {

     app.activeDocument.activeLayer = theSO;

     var idplacedLayerReplaceContents = stringIDToTypeID("placedLayerReplaceContents");

     var desc3 = new ActionDescriptor();

     var idnull = charIDToTypeID("null");

     desc3.putPath(idnull, new File(newFile));

     var idPgNm = charIDToTypeID("PgNm");

     desc3.putInteger(idPgNm, 1);

     executeAction(idplacedLayerReplaceContents, desc3, DialogModes.NO);

     return app.activeDocument.activeLayer;

}

But I've got error that said

General Photoshop error Occured. This functionality may not be available in this version of Photoshop.

for the executeAction(idplacedLayerReplaceContents, desc3, DialogModes.NO);

This is happening only when I add function through doProgrees();

I've try to figure it out for days, but with no success, because there is no enough search results for doProgress().

Photoshop version is CC 2017

I've also tried solution with WIndow palette with win.update(); but I've got flickering and is not working as expected.

Can anybody help me about this?

Thanks

c.pfaffenbichler
Community Expert
Community Expert
August 27, 2017

svemoguciyou may want to start a new thread discuss the issue.

Kmeanskeshav
Participating Frequently
January 13, 2017

How Can I Use This Script Just Copy Paste Or Edit Something Can Please Recommend Some Tutorial

ZeusBrands
Participant
December 8, 2016

How would I modify this script to replace multiple (and separate) smart objects in one PSD before it saves out each time.  I'm thinking it would ask for the user to define which files will replace each smart object as it cycles through. But, I do not know how to make the code prompt for all smart objects before it begins saving out.  Thanks for any help!

Participant
May 27, 2016

Hello there,

I have a question to this script.

#target photoshop

if (app.documents.length > 0) {

var myDocument = app.activeDocument;

var theName= myDocument.name.match(/(.*)\.[^\.]+$/)[1];

var thePath = myDocument.path;

var theLayer = myDocument.activeLayer;

// jpg options;

var jpgopts = new JPEGSaveOptions();

jpgopts.embedProfile = true;

jpgopts.formatOptions = FormatOptions.STANDARDBASELINE;

jpgopts.matte = MatteType.NONE;

jpgopts.quality = 8;

// check if layer is smart object;

if (theLayer.kind != "LayerKind.SMARTOBJECT") {alert ("selected layer is not a smart object")}

else {

// select files;

if ($.os.search(/windows/i) != -1) {var theFiles = File.openDialog ("please select files", "*.psd;*.tif;*.jpg", true)}

else {var theFiles = File.openDialog ("please select files", getFiles, true)};

if (theFiles) {

// work through the array;

          for (var m = 0; m < theFiles.length; m++) {

// replace smart object;

                    theLayer = replaceContents (theFiles, theLayer);

                    var theNewName = theFiles.name.match(/(.*)\.[^\.]+$/)[1];

//save jpg;

                    myDocument.saveAs((new File(thePath+"/"+theName+"_"+theNewName+".jpg")),jpgopts,true);

                    }

          }

}

};

////// get psds, tifs and jpgs from files //////

function getFiles (theFile) {

     if (theFile.name.match(/\.(psd|tif)$/i) != null || theFile.constructor.name == "Folder") {

          return true

          };

     };

////// replace contents //////

function replaceContents (newFile, theSO) {

app.activeDocument.activeLayer = theSO;

// =======================================================

var idplacedLayerReplaceContents = stringIDToTypeID( "placedLayerReplaceContents" );

    var desc3 = new ActionDescriptor();

    var idnull = charIDToTypeID( "null" );

    desc3.putPath( idnull, new File( newFile ) );

    var idPgNm = charIDToTypeID( "PgNm" );

    desc3.putInteger( idPgNm, 1 );

executeAction( idplacedLayerReplaceContents, desc3, DialogModes.NO );

return app.activeDocument.activeLayer

};

I´m not a coder and would like to know if someone know how to replace the following part of the code:

// select files;

if ($.os.search(/windows/i) != -1) {var theFiles = File.openDialog ("please select files", "*.psd;*.tif;*.jpg", true)}

else {var theFiles = File.openDialog ("please select files", getFiles, true)};

if (theFiles) {

I would like to have the script running without asking to select the files. I would like to define a folder directly within the script. For example, C:/documents/images/...

so that the script immediatly starts without asking for anything.

Can anybody help me out ?

Best wishes

Olli

c.pfaffenbichler
Community Expert
Community Expert
May 27, 2016

You could try

var theFiles = Folder(/* insert the correct path here */).getFiles(/\.(jpg|tif|psd)$/i);

Participant
May 27, 2016

Thank you so much for your reply.

I tried it but it did not work

.......

// select files;

if ($.os.search(/windows/i) != -1) {var theFiles = Folder(/E:\images\).getFiles(/\.(jpg|tif|psd)$/i)}

else {var theFiles = File.openDialog ("please select files", getFiles, true)};

if (theFiles) {

// work through the array;

.......

JJMack
Community Expert
Community Expert
January 31, 2014

SamanthaLee706 wrote:

Hello,

This is what I have:

  • a mockup file of a book with the cover image set as a transformed smart object
  • a folder of images resized to fit said smart object

This is what I would like a script to do (if possible):

  • for every image in said folder
  • replace smart object with images
  • save each new mockup (one for each new image) as a PSD file.

We have to create over 40 book, CD, DVD, and Blu-Ray mockups for each flyer we do.  Smart Objects help streamline it a little but I'm just going through and using an action right now, which I know is less than ideal.  I don't mind if the file names aren't what I need them to be, so incremental file naming would be fine because I could rename them all later.

Any suggestions on how I could streamline this process without having to manually replace and save?

You should be able to do what you want using Photoshop Data driven graphics with a PSD template with defined variables and a CSV file.  If you don't want to use that or create CSV files.  A simple template psd file and a script can also do what you want. 

If you look at my Photo Collage Toolkit for Photoshop you will find it contains a some batch scripts. BatchOneImageCollage, BatchMultiImageCollage and BatchPicturePackage to batch populate collage templates.

Photo Collage Toolkit.

Photoshop scripting is powerful and I believe this package demonstrates this.

The package includes four simple rules to follow when making Photo Collage Template PSD files so they will be compatible with my Photoshop scripts.

There are twelve scripts in this package they provide the following functions:

  1. TestCollageTemplate.jsx - Used to test a Photo Collage Template while you are making it with Photoshop.
  2. CollageTemplateBuilder.jsx - Can build Templates compatible with this toolkit's scripts.
  3. LayerToAlphaChan.jsx - Used to convert a Prototype Image Layer stack into a template document.
  4. InteractivePopulateCollage.jsx - Used to interactively populate Any Photo Collage template. Offers most user control inserting pictures and text.
  5. ReplaceCollageImage.jsx - use to replace a populated collage image Smart Object layer with an other image correctly resized and positioned.
  6. ChangeTextSize.jsx - This script can be used to change Image stamps text size when the size used by the populating did not work well.
  7. PopulateCollageTemplate.jsx - Used to Automatically populate a Photo Collage template and leave the populated copy open in Photoshop.
  8. BatchOneImageCollage.jsx - Used to Automatically Batch Populate Collage templates that only have one image inserted. The Collage or Image may be stamped with text.
  9. BatchMultiImageCollage.jsx - Used to Automatically Batch Populate Any Photo Collage template with images in a source image folder. Easier to use than the interactive script. Saved collages can be tweaked.
  10. BatchPicturePackage.jsx - Used to Automatically Batch Populate Any Photo Collage template with an image in a source image folder
  11. PasteImageRoll.jsx - Paste Images into a document to be print on roll paper.
  12. PCTpreferences.jsx - Edit This File to Customize Collage Populating scripts default setting and add your own Layer styles.


Documentation and Examples

JJMack
SarahFaithMorris1600
Known Participant
January 31, 2014

Tried 'BatchOneImageCollage" before and this is what popped up:

JJMack
Community Expert
Community Expert
January 31, 2014

Try running the script from Photoshop instead of the extendscript toolkit it has some issues or comment out "#target photoshop".  Also note my Scripts place in files from a straight on perspective.  Image areas can have any shape and appear to have a perspective like your covers.  However to achieve the correct perspective the image needs to have it to begin with or the placed smart object layer needs to have their associated transform tweaked to have the corners matched with the area.  If the cover perspective is not extreme the placed images may look good without tweaking the transform.. Any size image will be resized to fit the image location.  The script work best when image and image areas have the same aspect ratios,  However they don't need to be.

Since you have only a single image and all your source images are the same size and resolution.  You can write a Batch script that would replace the smart object layers embedded object in a template with a placed and transformed image the script just needs to know the name of the template's smart object layer.  All source images would need to be exactly the same size and resolution. You would need a template psd file for each image size you want to use.

JJMack
c.pfaffenbichler
Community Expert
Community Expert
January 31, 2014

Have you found a Scripting solution yet?

SarahFaithMorris1600
Known Participant
January 31, 2014

Yes - sort of - thank you!  My ultimate goal in all this is automating each type of mockup we need to create (CD, DVD, Blu-Ray, Book, all different facings, etc).

I am using a script (that I believe you wrote) but I can only use it for certain circumstances (and for paperback right facing books only) because sometimes I would need to create the spine of the DVD, book, or side panel of the CD, which would involve more than one smart object and creating those elements would take just as much work on my end creating the folder of files than scripting would help.  I replaced what you suggested in the other thread and it works now with selecting items in a folder.

For a hardcover book facing right, There is only ONE more step I would need to add to the script to make this type of mockup fully automated and that is to have the option to change the color of the little bit of back cover that's showing (the highlighted layer in the example below) Which would involve just a dialog to modify that one layer.  I would need to be to select the new color (to match the cover, obviously), and then the script can continue on with saving the new PSD as normal.

Any suggestions on how i can add to this script to be able to change that layer?  I don't want to get too complicated with all of this, but we do this EVERY MONTH so it would be of great use to us.

Thanks in advance for sharing your knowledge with the Adobe community!

c.pfaffenbichler
Community Expert
Community Expert
January 31, 2014

What are the unmistakeable characteristics of that Layer?

It seems to share its name with another one, but is it always the lowermost Layer?

Or at least the lowermost Solid Color Layer?