Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save stephenjwatkins/41a2547d4a249527692550bc4096afd6 to your computer and use it in GitHub Desktop.
Save stephenjwatkins/41a2547d4a249527692550bc4096afd6 to your computer and use it in GitHub Desktop.
Photoshop script to replace a Smart Object within a PSD using "Place Embedded" with specified image and saves result as a JPG. Preserves transformations.
// Photoshop script to replace a Smart Object within a PSD using "Place Embedded" with specified image and saves result as a JPG. Preserves transformations.
// 2025. Use at your own risk
// Can be run in an automated fashion on Mac via AppleScript:
// osascript -e "tell application \"Adobe Photoshop 2025\" to activate do javascript of file \"replace_smartobject_psd_placeembedded.jsx\""
#target photoshop
var mockupFilePath = "~/mockup.psd";
var designFilePath = "~/design.png";
var exportFilePath = "~/export.jpg";
var jpegOptions = new JPEGSaveOptions();
jpegOptions.quality = 9;
jpegOptions.embedColorProfile = true;
jpegOptions.matte = MatteType.NONE;
app.open(new File(mockupFilePath));
var myDocument = app.activeDocument;
var theName = myDocument.name.match(/(.*)\.[^\.]+$/)[1];
var thePath = myDocument.path;
var smartObject = findSmartObject(app.activeDocument);
var theLayer = smartObject;
myDocument.activeLayer = theLayer;
if (theLayer.kind != "LayerKind.SMARTOBJECT") {
alert("selected layer is not a smart object");
} else {
theLayer = editSmartObjectAndPlaceEmbedded(designFilePath, theLayer);
myDocument.saveAs(new File(exportFilePath), jpegOptions, true);
app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
}
function findSmartObject(doc) {
try {
// Find all smart objects in the document
var smartObjects = findSmartObjects(doc);
if (smartObjects.length === 0) {
alert("No smart objects found in the document.");
return;
}
// If multiple smart objects exist, let user choose which one to replace
var targetSmartObject;
if (smartObjects.length === 1) {
targetSmartObject = smartObjects[0];
} else {
// For multiple smart objects, select the first one
// You can modify this logic to let user choose specific smart object
targetSmartObject = smartObjects[0];
alert("Multiple smart objects found. Using the first one.");
}
return targetSmartObject;
} catch (error) {
throw new Error("Failed to replace smart object content: " + error.message);
}
}
function findSmartObjects(doc) {
var smartObjects = [];
try {
// Search through all layers recursively
function searchLayers(layers) {
for (var i = 0; i < layers.length; i++) {
var layer = layers[i];
// Check if layer is a smart object
if (layer.kind === LayerKind.SMARTOBJECT) {
smartObjects.push(layer);
}
// If layer is a group, search its layers
if (layer.typename === "LayerSet") {
searchLayers(layer.layers);
}
}
}
searchLayers(doc.layers);
} catch (error) {
throw new Error("Error searching for smart objects: " + error.message);
}
return smartObjects;
}
function editSmartObjectAndPlaceEmbedded(newFile, smartObjectLayer) {
try {
// Store reference to the main document
var mainDocument = app.activeDocument;
// Edit the smart object contents using ActionDescriptor
editSmartObjectContents(smartObjectLayer);
// Now we're inside the smart object document
var smartObjectDoc = app.activeDocument;
// Clear existing content (optional - you can modify this based on your needs)
// smartObjectDoc.layers[0].delete();
// Place the new file as embedded
placeEmbedded(newFile);
// Save changes to the smart object
smartObjectDoc.save();
// Close the smart object document and return to main document
smartObjectDoc.close(SaveOptions.SAVECHANGES);
// Return to the main document
app.activeDocument = mainDocument;
return smartObjectLayer;
} catch (error) {
alert("Error editing smart object: " + error.message);
// Try to return to main document if there was an error
try {
app.activeDocument = mainDocument;
} catch (e) {
// If we can't return to main document, try to close any open smart object
if (app.documents.length > 1) {
app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
}
}
throw error;
}
}
function placeEmbedded(filePath) {
var actDesc = new ActionDescriptor();
actDesc.putPath(charIDToTypeID("null"), new File(filePath));
actDesc.putEnumerated(
charIDToTypeID("FTcs"),
charIDToTypeID("QCSt"),
charIDToTypeID("Qcsa")
);
executeAction(charIDToTypeID("Plc "), actDesc, DialogModes.NO);
}
function editSmartObjectContents(smartObjectLayer) {
try {
// Make the smart object layer active
app.activeDocument.activeLayer = smartObjectLayer;
// Use ActionDescriptor to edit smart object contents
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated(
charIDToTypeID("Lyr "),
charIDToTypeID("Ordn"),
charIDToTypeID("Trgt")
);
desc.putReference(charIDToTypeID("null"), ref);
desc.putEnumerated(
charIDToTypeID("Usng"),
charIDToTypeID("Plc "),
charIDToTypeID("Plc ")
);
executeAction(
stringIDToTypeID("placedLayerEditContents"),
desc,
DialogModes.NO
);
} catch (error) {
throw new Error("Failed to edit smart object contents: " + error.message);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment