Copy link to clipboard
Copied
Hi everyone,
My knowledge of coding is unfortunately very minimal, and I've been having a really hard time for the better part of the day trying to figure out how to do this following other answers I've seen on here.
I have a mock up PSD that has 2 smart objects within it and I have 2 folders each with an equal number of images in them.
I need a script that can replace the first smart object with an image from the first folder and the second smart object with an image from the second folder and then export the whole thing. There's about 700~ images in both of the folders so I need it to run through all of them if possible.
As an example it would export like this.
Fortunately the images have mirrored names across the folders (i.e image1-side-a and image1-side-b) so I don't need the script to look for filenames or anything like that.
Any help would be extremely appreciated.
@NelNelD – I have updated the code to a 1.1 version, the lower smart object layer is now removed.
EDIT: Let me know how it goes. I have now updated to a 1.2 version so that all layers in the smart object are removed, except the top layer.
I have updated the code to version 1.3 to remove any photoshop:DocumentAncestors metadata build-up in the smart objects and or main PSD file which may bloat the file size after multiple uses.
Here is the revised script for your specific template and assets:
/*
Video Game Smart Object Layer Replacements to PNG.jsx
Version 1.0 - 22nd June 2024, Stephen Marsh
Based on:
https://community.adobe.com/t5/photoshop-ecosystem-discussions/batch-script-to-replace-2-smart-objects-and-save-the-final-image/m-p/13728400
*/
#target photoshop
(function () {
try {
var selectFile = File.openDialog("Select the template file:");
open(selectFile);
...
Copy link to clipboard
Copied
Can you post a screenshot of the layer panel, or better yet, provide the PSD and an image from each folder to help any volunteers that may try to assist?
You may not even need to do this with smart object replacement, the late JJMack's Photo Collage Toolkit may do the job:
Copy link to clipboard
Copied
Copy link to clipboard
Copied
Is there a particular reason why the mockup uses an embedded smart object PSB inside an embedded smart object PSB? Could the mockup file be simplified to only have one embedded smart object PSB file at the top level for each layer (no nesting/Matryoshka doll)?
Copy link to clipboard
Copied
I didn't realise that was a smart object nested inside the original smart object. When I updated the original smart object, I was just dragging + dropping the PNGs so I assume that is what created the nested smart object. My smart object knowledge in general is rather lacking unfortunately.
To answer your question though, yes the mockup file can be simplied if that makes things easier.
Copy link to clipboard
Copied
Could you provide a small number of the replacement files?
What are the locations (relative to the psd) and names of the folders?
Copy link to clipboard
Copied
Try this script and the template that I simplified from your original:
/*
2 Input Folder Smart Object Layer Replacements to PSD.jsx
Version 1.3 - 19th April 2023, Stephen Marsh
https://community.adobe.com/t5/photoshop-ecosystem-discussions/batch-script-to-replace-2-smart-objects-and-save-the-final-image/m-p/13728400
*/
#target photoshop
(function () {
try {
if (app.documents.length === 1) {
// Image 1 input folder
var folder1 = Folder.selectDialog("Select the Side-1 image folder:");
if (folder1 === null) {
//alert('Script cancelled!');
return;
}
// Image 2 input folder
var folder2 = Folder.selectDialog("Select the Side-2 image folder:");
if (folder2 === null) {
//alert('Script cancelled!');
return;
}
// Validate input folder selection
var validateInputDir = (folder1.fsName === folder2.fsName);
if (validateInputDir === true) {
alert("Script cancelled as both the input folders are the same!");
return;
}
// Limit the file input as required
var list1 = folder1.getFiles(/\.(jpe?g|tif?f|psd|psb|png)$/i);
var list2 = folder2.getFiles(/\.(jpe?g|tif?f|psd|psb|png)$/i);
// Alpha-numeric sort
list1.sort();
list2.sort();
// Validate that folder 1 & 2 lists are not empty
var validateEmptyList = (list1.length > 0 && list2.length > 0);
if (validateEmptyList === false) {
alert("Script cancelled as one of the input folders is empty!");
return;
}
// Validate that the item count in folder 1 & 2 matches
var validateListLength = (list1.length === list2.length);
if (validateListLength === false) {
alert("Script cancelled as the input folders don't have equal quantities of images!");
return;
}
// Output folder
var saveFolder = Folder.selectDialog("Please select the folder to save to...");
if (saveFolder === null) {
//alert('Script cancelled!');
return;
}
// Save and set the dialog display settings
var savedDisplayDialogs = app.displayDialogs;
app.displayDialogs = DialogModes.NO;
// PSD save options
var psdOptions = new PhotoshopSaveOptions();
psdOptions.embedColorProfile = true;
psdOptions.alphaChannels = true;
psdOptions.layers = true;
psdOptions.spotColors = true;
// Set the file processing counter
var fileCounter = 0;
// Perform the SO replacements
for (var i = 0; i < list1.length; i++) {
selectBackLayer();
activeDocument.activeLayer = activeDocument.layers["Side-1"];
if (activeDocument.activeLayer.kind === LayerKind.SMARTOBJECT) {
app.runMenuItem(stringIDToTypeID('placedLayerEditContents'));
placeFile(list1[i], 100);
var side1Name = activeDocument.activeLayer.name;
removeAllLayersExceptFrontLayer();
removeAncestorsMD();
activeDocument.close(SaveOptions.SAVECHANGES);
} else {
alert("The layer isn't a Smart Object!");
}
activeDocument.activeLayer = activeDocument.layers["Side-2"];
if (activeDocument.activeLayer.kind === LayerKind.SMARTOBJECT) {
app.runMenuItem(stringIDToTypeID('placedLayerEditContents'));
placeFile(list2[i], 100);
var side2Name = activeDocument.activeLayer.name;
removeAllLayersExceptFrontLayer();
removeAncestorsMD();
activeDocument.close(SaveOptions.SAVECHANGES);
} else {
alert("The layer isn't a Smart Object!");
}
activeDocument.saveAs(new File(saveFolder + '/' + side1Name + "_" + side2Name + '.psd'), psdOptions);
// Advance the counter
fileCounter++;
}
removeAncestorsMD();
activeDocument.close(SaveOptions.SAVECHANGES);
// End of script
app.displayDialogs = savedDisplayDialogs;
app.beep();
alert('Script completed!' + '\r' + fileCounter + ' SO replacement PSD files of ' + list1.length + ' input file sets saved to:' + '\r' + saveFolder.fsName);
} else {
alert("Only the template file should be open!");
}
} catch (e) {
alert("Error!" + "\r" + e + ' ' + e.line);
}
///// Functions /////
function placeFile(file, scale) {
try {
var idPlc = charIDToTypeID("Plc ");
var desc2 = new ActionDescriptor();
var idnull = charIDToTypeID("null");
desc2.putPath(idnull, new File(file));
var idFTcs = charIDToTypeID("FTcs");
var idQCSt = charIDToTypeID("QCSt");
var idQcsa = charIDToTypeID("Qcsa");
desc2.putEnumerated(idFTcs, idQCSt, idQcsa);
var idOfst = charIDToTypeID("Ofst");
var desc3 = new ActionDescriptor();
var idHrzn = charIDToTypeID("Hrzn");
var idPxl = charIDToTypeID("#Pxl");
desc3.putUnitDouble(idHrzn, idPxl, 0.000000);
var idVrtc = charIDToTypeID("Vrtc");
var idPxl = charIDToTypeID("#Pxl");
desc3.putUnitDouble(idVrtc, idPxl, 0.000000);
var idOfst = charIDToTypeID("Ofst");
desc2.putObject(idOfst, idOfst, desc3);
var idWdth = charIDToTypeID("Wdth");
var idPrc = charIDToTypeID("#Prc");
desc2.putUnitDouble(idWdth, idPrc, scale);
var idHght = charIDToTypeID("Hght");
var idPrc = charIDToTypeID("#Prc");
desc2.putUnitDouble(idHght, idPrc, scale);
var idAntA = charIDToTypeID("AntA");
desc2.putBoolean(idAntA, true);
executeAction(idPlc, desc2, DialogModes.NO);
} catch (e) {}
}
function selectBackLayer() {
app.activeDocument.activeLayer = app.activeDocument.layers[app.activeDocument.layers.length - 1];
}
function removeAllLayersExceptFrontLayer() {
// Remove all layers except the top/front layer
for (var i = activeDocument.layers.length - 1; i >= 1; i--) {
var theLayer = activeDocument.layers[i];
theLayer.remove();
}
}
function removeAllLayersExceptBackLayer() {
// Remove all layers except the bottom/back layer
for (var i = activeDocument.layers.length - 2; i >= 0; i--) {
var theLayer = activeDocument.layers[i];
theLayer.remove();
}
}
function removeAncestorsMD() {
// https://prepression.blogspot.com/2017/06/metadata-bloat-photoshopdocumentancestors.html
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();
}
}());
You didn't mention the final file format and I forgot to ask, so this v1.0 script uses PSD.
https://prepression.blogspot.com/2017/11/downloading-and-installing-adobe-scripts.html#Photoshop
Copy link to clipboard
Copied
@NelNelD , in the Script @Stephen_A_Marsh generously posted a selectDialog is used to identify the Folders with the replacement images – depending on whether there is a definite position (either on your computer in general or relative to the open psd) and on how frequent the task needs to be performed it might improve efficiency to hard-code that location into the Script.
Copy link to clipboard
Copied
@c.pfaffenbichler – Agreed 100%, much more efficient to not have to select the two input folders or the output folder!
Copy link to clipboard
Copied
Unfortunately as I work a lot between multiple computers / laptops, I can't specify an exact path as it will be changing constantly.
Does having to specify the folders with a dialog box slow down the process by much?
Copy link to clipboard
Copied
It only "slows things down" once per run, for the time that it takes to select the three folders. It is not so much about speed, just the tedious chore of having to select three folders! :]
If the PNG files were always saved next to the PSD template, or in a folder next to the template, or in a consistent relative location to the PSD template, then at least the export location could be automated, even on different computers. The same goes for the input folders, a relative path can be used if it is consistent to the PSD template.
Copy link to clipboard
Copied
This is absolutely incredible, thank you so much.
Sorry I forgot to mention the final file format. I need them to be exported as PNGs, is that hard to change?
Copy link to clipboard
Copied
No, it's not hard to change for PNG.
Copy link to clipboard
Copied
@NelNelD – Here is a version that uses Export > Save for Web to create PNG files.
/*
2 Input Folder Smart Object Layer Replacements to PNG.jsx
Version 1.3 - 19th April 2023, Stephen Marsh
https://community.adobe.com/t5/photoshop-ecosystem-discussions/batch-script-to-replace-2-smart-objects-and-save-the-final-image/m-p/13728400
*/
#target photoshop
(function () {
try {
if (app.documents.length === 1) {
// Image 1 input folder
var folder1 = Folder.selectDialog("Select the Side-1 image folder:");
if (folder1 === null) {
//alert('Script cancelled!');
return;
}
// Image 2 input folder
var folder2 = Folder.selectDialog("Select the Side-2 image folder:");
if (folder2 === null) {
//alert('Script cancelled!');
return;
}
// Validate input folder selection
var validateInputDir = (folder1.fsName === folder2.fsName);
if (validateInputDir === true) {
alert("Script cancelled as both the input folders are the same!");
return;
}
// Limit the file input as required
var list1 = folder1.getFiles(/\.(jpe?g|tif?f|psd|psb|png)$/i);
var list2 = folder2.getFiles(/\.(jpe?g|tif?f|psd|psb|png)$/i);
// Alpha-numeric sort
list1.sort();
list2.sort();
// Validate that folder 1 & 2 lists are not empty
var validateEmptyList = (list1.length > 0 && list2.length > 0);
if (validateEmptyList === false) {
alert("Script cancelled as one of the input folders is empty!");
return;
}
// Validate that the item count in folder 1 & 2 matches
var validateListLength = (list1.length === list2.length);
if (validateListLength === false) {
alert("Script cancelled as the input folders don't have equal quantities of images!");
return;
}
// Output folder
var saveFolder = Folder.selectDialog("Please select the folder to save to...");
if (saveFolder === null) {
//alert('Script cancelled!');
return;
}
// Save and set the dialog display settings
var savedDisplayDialogs = app.displayDialogs;
app.displayDialogs = DialogModes.NO;
// PNG export options
var pngOptions = new ExportOptionsSaveForWeb();
pngOptions.PNG8 = false;
pngOptions.transparency = true;
pngOptions.interlaced = false;
pngOptions.quality = 100;
pngOptions.includeProfile = true;
pngOptions.format = SaveDocumentType.PNG;
// Set the file processing counter
var fileCounter = 0;
// Perform the SO replacements
for (var i = 0; i < list1.length; i++) {
selectBackLayer();
activeDocument.activeLayer = activeDocument.layers["Side-1"];
if (activeDocument.activeLayer.kind === LayerKind.SMARTOBJECT) {
app.runMenuItem(stringIDToTypeID('placedLayerEditContents'));
placeFile(list1[i], 100);
var side1Name = activeDocument.activeLayer.name;
removeAllLayersExceptFrontLayer();
removeAncestorsMD();
activeDocument.close(SaveOptions.SAVECHANGES);
} else {
alert("The layer isn't a Smart Object!");
}
activeDocument.activeLayer = activeDocument.layers["Side-2"];
if (activeDocument.activeLayer.kind === LayerKind.SMARTOBJECT) {
app.runMenuItem(stringIDToTypeID('placedLayerEditContents'));
placeFile(list2[i], 100);
var side2Name = activeDocument.activeLayer.name;
removeAllLayersExceptFrontLayer();
removeAncestorsMD();
activeDocument.close(SaveOptions.SAVECHANGES);
} else {
alert("The layer isn't a Smart Object!");
}
activeDocument.exportDocument(File(saveFolder + "/" + side1Name + "_" + side2Name + ".png"), ExportType.SAVEFORWEB, pngOptions);
// Advance the counter
fileCounter++;
}
removeAncestorsMD();
activeDocument.close(SaveOptions.SAVECHANGES);
// End of script
app.displayDialogs = savedDisplayDialogs;
app.beep();
alert('Script completed!' + '\r' + fileCounter + ' SO replacement PNG files of ' + list1.length + ' input file sets saved to:' + '\r' + saveFolder.fsName);
} else {
alert("Only the template file should be open!");
}
} catch (e) {
alert("Error!" + "\r" + e + ' ' + e.line);
}
///// Functions /////
function placeFile(file, scale) {
try {
var idPlc = charIDToTypeID("Plc ");
var desc2 = new ActionDescriptor();
var idnull = charIDToTypeID("null");
desc2.putPath(idnull, new File(file));
var idFTcs = charIDToTypeID("FTcs");
var idQCSt = charIDToTypeID("QCSt");
var idQcsa = charIDToTypeID("Qcsa");
desc2.putEnumerated(idFTcs, idQCSt, idQcsa);
var idOfst = charIDToTypeID("Ofst");
var desc3 = new ActionDescriptor();
var idHrzn = charIDToTypeID("Hrzn");
var idPxl = charIDToTypeID("#Pxl");
desc3.putUnitDouble(idHrzn, idPxl, 0.000000);
var idVrtc = charIDToTypeID("Vrtc");
var idPxl = charIDToTypeID("#Pxl");
desc3.putUnitDouble(idVrtc, idPxl, 0.000000);
var idOfst = charIDToTypeID("Ofst");
desc2.putObject(idOfst, idOfst, desc3);
var idWdth = charIDToTypeID("Wdth");
var idPrc = charIDToTypeID("#Prc");
desc2.putUnitDouble(idWdth, idPrc, scale);
var idHght = charIDToTypeID("Hght");
var idPrc = charIDToTypeID("#Prc");
desc2.putUnitDouble(idHght, idPrc, scale);
var idAntA = charIDToTypeID("AntA");
desc2.putBoolean(idAntA, true);
executeAction(idPlc, desc2, DialogModes.NO);
} catch (e) {}
}
function selectBackLayer() {
app.activeDocument.activeLayer = app.activeDocument.layers[app.activeDocument.layers.length - 1];
}
function removeAllLayersExceptFrontLayer() {
// Remove all layers except the top/front layer
for (var i = activeDocument.layers.length - 1; i >= 1; i--) {
var theLayer = activeDocument.layers[i];
theLayer.remove();
}
}
function removeAllLayersExceptBackLayer() {
// Remove all layers except the bottom/back layer
for (var i = activeDocument.layers.length - 2; i >= 0; i--) {
var theLayer = activeDocument.layers[i];
theLayer.remove();
}
}
function removeAncestorsMD() {
// https://prepression.blogspot.com/2017/06/metadata-bloat-photoshopdocumentancestors.html
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();
}
}());
Copy link to clipboard
Copied
This is amazing, thank you so much.
I've just run into another issue, because the files being used for the source images are transparent PNGs with a shadow, it seems they're overlapping in the smart object causing the shadow to get increasingly darker with every loop.
Is it possible to include a part of the script that removes the previous layer within the smart object before / after it adds the new file?
I've attached 5 images that show the shadow getting progressively darker, it's most noticeable on the left of the pillows.
Copy link to clipboard
Copied
@NelNelD – I have updated the code to a 1.1 version, the lower smart object layer is now removed.
EDIT: Let me know how it goes. I have now updated to a 1.2 version so that all layers in the smart object are removed, except the top layer.
I have updated the code to version 1.3 to remove any photoshop:DocumentAncestors metadata build-up in the smart objects and or main PSD file which may bloat the file size after multiple uses.
Copy link to clipboard
Copied
Sorry for my late reply, this worked absolutely perfectly.
Thank you so much for all of your help.
Copy link to clipboard
Copied
Hi @Stephen_A_Marsh ! I wonder if is there any way to addapt the script you post in this thread to my needs. I spent more than two hours without success (Sorry, i'm not good with coding).
Here is what i would need if possible:
I have a psd template "3D Box.psd" which is a game box with two smart objects: One is the Box Front, and the other is the Box Spine.
I also have three folders on my computer:
- Box - Front (With all images of the box front)
- Box - Spine (With all images of the box spine)
- Results (Output folder for all the images that i would like the script generates in .png format)
I wonder if is possible the script creates a 3D Box called the same way as the Front Box and Spines Image. And the same for all images in the folders.
Example of the job done manually by exporting one 3D Box by one.
Hope you can help me. Thank in advance!
Copy link to clipboard
Copied
Hi @Stephen_A_Marsh ! I wonder if is there any way to addapt the script you post in this thread to my needs.
By @ci2own
Please post the template .psd file and at least 2 sets of 2 replacement images and I'll take a look. You can either upload to the forum or send me a private message with the assets if you don't wish to post them publicly.
Copy link to clipboard
Copied
Sent you a PM. with the template. Thanks.
Copy link to clipboard
Copied
Here is the revised script for your specific template and assets:
/*
Video Game Smart Object Layer Replacements to PNG.jsx
Version 1.0 - 22nd June 2024, Stephen Marsh
Based on:
https://community.adobe.com/t5/photoshop-ecosystem-discussions/batch-script-to-replace-2-smart-objects-and-save-the-final-image/m-p/13728400
*/
#target photoshop
(function () {
try {
var selectFile = File.openDialog("Select the template file:");
open(selectFile);
// Image 1 input folder
var theSpine = Folder.selectDialog("Select the Spine image folder:");
if (theSpine === null) {
//alert('Script cancelled!');
return;
}
// Image 2 input folder
var theFront = Folder.selectDialog("Select the Front image folder:");
if (theFront === null) {
//alert('Script cancelled!');
return;
}
// Validate image folder selection
var validateInputDir = (theSpine.fsName === theFront.fsName);
if (validateInputDir === true) {
alert("Script cancelled as both the input folders are the same!");
return;
}
// Limit the file formats
var list1 = theSpine.getFiles(/\.(jpe?g|tif?f|psd|psb|png|webp)$/i);
var list2 = theFront.getFiles(/\.(jpe?g|tif?f|psd|psb|png|webp)$/i);
// Alpha-numeric sort
list1.sort();
list2.sort();
// Validate that folder 1 & 2 lists are not empty
var validateEmptyList = (list1.length > 0 && list2.length > 0);
if (validateEmptyList === false) {
alert("Script cancelled as one of the input folders is empty!");
return;
}
// Validate that the item count in folder 1 & 2 matches
var validateListLength = (list1.length === list2.length);
if (validateListLength === false) {
alert("Script cancelled as the input folders don't have equal quantities of images!");
return;
}
// Output folder
var saveFolder = Folder.selectDialog("Select the folder to save the PNG files to...");
if (saveFolder === null) {
//alert('Script cancelled!');
return;
}
// Save and set the dialog display settings
var savedDisplayDialogs = app.displayDialogs;
app.displayDialogs = DialogModes.NO;
// PNG export options
var pngOptions = new ExportOptionsSaveForWeb();
pngOptions.PNG8 = false;
pngOptions.transparency = true;
pngOptions.interlaced = false;
pngOptions.quality = 100;
pngOptions.includeProfile = true;
pngOptions.format = SaveDocumentType.PNG;
// Set the file processing counter
var fileCounter = 0;
// 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, -1];
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();
// Perform the SO replacements
for (var i = 0; i < list1.length; i++) {
// Box Spine
app.activeDocument.activeLayer = app.activeDocument.layerSets.getByName('Product Box').layerSets.getByName('Spine').layers.getByName('Spine');
app.runMenuItem(stringIDToTypeID('placedLayerEditContents'));
app.activeDocument.activeLayer = app.activeDocument.layers[0];
placeFile(list1[i], 100);
removeAncestorsMD();
var theName = app.activeDocument.activeLayer.name;
activeDocument.close(SaveOptions.SAVECHANGES);
// Box Front
app.activeDocument.activeLayer = app.activeDocument.layerSets.getByName('Product Box').layerSets.getByName('Box Front').layers.getByName('Box Front');
app.runMenuItem(stringIDToTypeID('placedLayerEditContents'));
app.activeDocument.activeLayer = app.activeDocument.layers[0];
placeFile(list2[i], 100);
removeAncestorsMD();
activeDocument.close(SaveOptions.SAVECHANGES);
// Remove unwanted paste/place metadata
removeAncestorsMD();
// Save for Web to PNG
activeDocument.exportDocument(File(saveFolder + "/" + theName + ".png"), ExportType.SAVEFORWEB, pngOptions);
// Revert
executeAction(stringIDToTypeID("revert"), undefined, DialogModes.NO);
// Advance the counter
fileCounter++;
}
// Ensure Photoshop has focus before closing the running script notification window
app.bringToFront();
working.close();
// Close the template
activeDocument.close(SaveOptions.DONOTSAVECHANGES);
// Restore the Photoshop panels
app.togglePalettes();
// End of script
app.displayDialogs = savedDisplayDialogs;
app.beep();
alert('Script completed!' + '\r' + fileCounter + ' SO replacement PNG files of ' + list1.length + ' input file sets saved to:' + '\r' + saveFolder.fsName);
} catch (e) {
alert("Error!" + "\r" + e + ' ' + e.line);
}
///// Functions /////
function placeFile(file, scale) {
try {
var idPlc = charIDToTypeID("Plc ");
var desc2 = new ActionDescriptor();
var idnull = charIDToTypeID("null");
desc2.putPath(idnull, new File(file));
var idFTcs = charIDToTypeID("FTcs");
var idQCSt = charIDToTypeID("QCSt");
var idQcsa = charIDToTypeID("Qcsa");
desc2.putEnumerated(idFTcs, idQCSt, idQcsa);
var idOfst = charIDToTypeID("Ofst");
var desc3 = new ActionDescriptor();
var idHrzn = charIDToTypeID("Hrzn");
var idPxl = charIDToTypeID("#Pxl");
desc3.putUnitDouble(idHrzn, idPxl, 0.000000);
var idVrtc = charIDToTypeID("Vrtc");
var idPxl = charIDToTypeID("#Pxl");
desc3.putUnitDouble(idVrtc, idPxl, 0.000000);
var idOfst = charIDToTypeID("Ofst");
desc2.putObject(idOfst, idOfst, desc3);
var idWdth = charIDToTypeID("Wdth");
var idPrc = charIDToTypeID("#Prc");
desc2.putUnitDouble(idWdth, idPrc, scale);
var idHght = charIDToTypeID("Hght");
var idPrc = charIDToTypeID("#Prc");
desc2.putUnitDouble(idHght, idPrc, scale);
var idAntA = charIDToTypeID("AntA");
desc2.putBoolean(idAntA, true);
executeAction(idPlc, desc2, DialogModes.NO);
} catch (e) {}
}
function removeAncestorsMD() {
// https://prepression.blogspot.com/2017/06/metadata-bloat-photoshopdocumentancestors.html
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();
}
}());
Copy link to clipboard
Copied
Wow! This script worked like a charm! 🙂
The only thing, in the result files, it adds a "-" between every word instead of a space.
 And also i realized doing some tests, the example images fits perfect on the result box, because i exported them from the same template, but when image size don't match the one in the smart object, it doesn't addapt it automatically:
 
Copy link to clipboard
Copied
Wow! This script worked like a charm! 🙂
The only thing, in the result files, it adds a "-" between every word instead of a space.
By @ci2own
The script uses Save for Web (Legacy) to create the PNG files. You would have the Unix filename compatibility default set which would be causing this. Use the Compatibility Naming Off setting rather than Default:
This setting is sticky, you just need to change it with an image open before running the script.
The alternative would be to use standard Save As/Save a Copy in the code rather than Save for Web (Legacy).
Copy link to clipboard
Copied
Thanks! Gonna check it.
Is there any way the script auto-adapts images to fit smart objects to avoid this when the images are smaller?:
Copy link to clipboard
Copied
Is there any way the script auto-adapts images to fit smart objects to avoid this when the images are smaller?:
By @ci2own
What is the PPI value of the files that place smaller? What are their pixel dimensions?
The current code places the image at 100% size (dictated by the resolution value). You are expected to correctly set up your assets to work with how smart object replacements are designed to work. I assumed that this was known as your three sets of example replacement files were perfect! :]
You can easily create an action to resize to a target pixel size and set the PPI value and save as PNG, then run through Batch to get all of your spine and cover assets correct before creating the mockups.
The alternative, rather than using place – the script could be changed to open the replacement image and then resize it and then copy/paste it into the smart object.