Copy link to clipboard
Copied
I have a large number of product images that have their shadows as a seperate image as can be seen here:
Each of these images follow the same naming conventions with a "_shadow" suffix at the end of the shadow images. Here's a quick screengrab of an example on how they look:
The main goal is to open up the non shadow images in photoshop, for example "lawn_mower.png" and then place the shadow image in the same file but below the main image layer. Once that is done, for it to export a .PSD of the resulting documnt with whilist inheriting the name of the original image which in this case would be "lawn_mower.psd" into a desination folder.
As I have over a 100 of these images that follow the same naming conventions. Is there a way to automate the above process in a single click so it searches the whole folder and performs the tasks similar to how the Image Processor works in photoshop?
I've tried going down the scripting route but have hit a wall as i'm not a programmer. but I think scripting would be the way to achieve this. If any further information is needed i'd be more than happy to provide it. Any help would be greatly, greatly appreciated 😊
// place "_shadow.png" in png and save psd;
// 2025, use it at your own risk;
var theFolder = Folder.selectDialog ("select folder");
if (theFolder) {
// psd options;
saveOpts = new PhotoshopSaveOptions();
saveOpts.embedColorProfile = true;
saveOpts.alphaChannels = false;
saveOpts.layers = true;
saveOpts.spotColors = true;
var theRegExp =/_shadow.png/i;
var theFiles = theFolder.getFiles(/\.(png)$/i)
for (var m = 0; m < theFiles.length; m++) {
var thisOne = theFiles[m];
if (String(thisOne).ma
...
Copy link to clipboard
Copied
Please provide a set of sample images (feel free to blur or downsample them).
Copy link to clipboard
Copied
// place "_shadow.png" in png and save psd;
// 2025, use it at your own risk;
var theFolder = Folder.selectDialog ("select folder");
if (theFolder) {
// psd options;
saveOpts = new PhotoshopSaveOptions();
saveOpts.embedColorProfile = true;
saveOpts.alphaChannels = false;
saveOpts.layers = true;
saveOpts.spotColors = true;
var theRegExp =/_shadow.png/i;
var theFiles = theFolder.getFiles(/\.(png)$/i)
for (var m = 0; m < theFiles.length; m++) {
var thisOne = theFiles[m];
if (String(thisOne).match(theRegExp) == null) {
var theShadow = String(thisOne).replace(/_*.png/, "_shadow.png");
if (File(theShadow).exists == true) {
var myImage = app.open(thisOne);
placeScaleRotateFile(theShadow, 0, 0, 100, 100, 0, false);
rasterizeSmartObject ();
moveLayerDown();
myImage.saveAs(new File(String(thisOne).replace(".png", ".psd")), saveOpts, true);
myImage.close(SaveOptions.DONOTSAVECHANGES)
}
}
}
};
////// place //////
function placeScaleRotateFile (file, xOffset, yOffset, theXScale, theYScale, theAngle, linked) {
var idPxl = charIDToTypeID( "#Pxl" );
var idPrc = charIDToTypeID( "#Prc" );
var idPlc = charIDToTypeID( "Plc " );
var desc5 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
desc5.putPath( idnull, new File( file ) );
var idFTcs = charIDToTypeID( "FTcs" );
var idQCSt = charIDToTypeID( "QCSt" );
var idQcsa = charIDToTypeID( "Qcsa" );
desc5.putEnumerated( idFTcs, idQCSt, idQcsa );
var idOfst = charIDToTypeID( "Ofst" );
var desc6 = new ActionDescriptor();
var idHrzn = charIDToTypeID( "Hrzn" );
desc6.putUnitDouble( idHrzn, idPxl, xOffset );
var idVrtc = charIDToTypeID( "Vrtc" );
desc6.putUnitDouble( idVrtc, idPxl, yOffset );
var idOfst = charIDToTypeID( "Ofst" );
desc5.putObject( idOfst, idOfst, desc6 );
var idWdth = charIDToTypeID( "Wdth" );
desc5.putUnitDouble( idWdth, idPrc, theYScale );
var idHght = charIDToTypeID( "Hght" );
desc5.putUnitDouble( idHght, idPrc, theXScale );
var idAngl = charIDToTypeID( "Angl" );
var idAng = charIDToTypeID( "#Ang" );
desc5.putUnitDouble( idAngl, idAng,theAngle );
if (linked == true) {
var idLnkd = charIDToTypeID( "Lnkd" );
desc5.putBoolean( idLnkd, true );
};
executeAction( idPlc, desc5, DialogModes.NO );
// get layerid;
var ref = new ActionReference();
ref.putProperty (stringIDToTypeID ("property"), stringIDToTypeID ("layerID"));
ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var layerDesc = executeActionGet(ref);
var layerID = layerDesc.getInteger (stringIDToTypeID ("layerID"));
return layerID;
};
////// move layer down //////
function moveLayerDown () {
var desc5 = new ActionDescriptor();
var ref3 = new ActionReference();
ref3.putEnumerated( charIDToTypeID( "Lyr " ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
desc5.putReference( charIDToTypeID( "null" ), ref3 );
var ref4 = new ActionReference();
ref4.putEnumerated( charIDToTypeID( "Lyr " ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Prvs" ) );
desc5.putReference( charIDToTypeID( "T " ), ref4 );
executeAction( charIDToTypeID( "move" ), desc5, DialogModes.NO );
};
////// rasterize the so //////
function rasterizeSmartObject () {
try {
var desc125 = new ActionDescriptor();
var ref83 = new ActionReference();
ref83.putEnumerated( charIDToTypeID( "Mn " ), charIDToTypeID( "MnIt" ), stringIDToTypeID( "rasterizePlaced" ) );
desc125.putReference( charIDToTypeID( "null" ), ref83 );
executeAction( charIDToTypeID( "slct" ), desc125, DialogModes.NO );
} catch (e) {}
};
edited 2025-01-26
Copy link to clipboard
Copied
So this works! A few questions:
After selecting the first file location it prompts another file explorer window which I assume is the destination folder but after running the script the folder remains empty whilst the .PSD's go in the original folder.
And is it possible for photoshop to close the document after the .PSD has been saved so that there isn't loads of images open?
Again, many thanks 😊
Copy link to clipboard
Copied
So this works! A few questions:
After selecting the first file location it prompts another file explorer window which I assume is the destination folder but after running the script the folder remains empty whilst the .PSD's go in the original folder.
And is it possible for photoshop to close the document after the .PSD has been saved so that there isn't loads of images open?
Again, many thanks 😊
By @Shaderss
No, there should be no second dialog.
And i asked you to provide a set ofsample images.
As for closing include
myImage.close(SaveOptions.DONOTSAVECHANGES)
edited
after the saving-line.
Copy link to clipboard
Copied
Okay no worries, yes after a few tries the second dialogue stopped appearing.
I'll add the closing part after the saving line.
I've attatched a Wetransfer of the sample images as it won't let me upload the zip file: https://we.tl/t-Y9SEHzi4Mn
Copy link to clipboard
Copied
I updated the Script.
I noticed that one image had a »_« before the suffix and that caused it not to be processed (see screenshot).
One point, though: The psd would overwrite an existing psd of the same name in the Folder.
If this is an issue the Script would need to include a check for existing files.
Copy link to clipboard
Copied
So i've tried using it with the above changes and it all works!! Thank you so much for helping me with this issue 😊
Copy link to clipboard
Copied
Sorry again, but the script also seems to stop after 5/6 exports. I've tried searching on the issue but can't find an issue.
Thanks again
Copy link to clipboard
Copied
You have some specific requirements, which the following generic script may or may not cover. The script can run an action to perform additional processing as required. File naming can be changed in the script code or in post using Bridge Batch Rename or other file renaming software.
// Save file path and name
var saveFile = File(outputFolder + '/' + combinedLayerNames); // Set the output path and filename
To:
// Save file path and name
var saveFile = File(outputFolder + '/' + app.activeDocument.layers[0].name); // Use the top layer to name the files