Copy link to clipboard
Copied
I'm using this script to replace content of a smart object with an image.
// Replace SmartObject 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;
};
The problem is that if the image is larger than the canvas within the smart layer the image would be placed as is, without it getting resized and fitted to the canvas. How can I make sure tha an image is always placed correctly?
I made some refinements. I found that it wasn't so much the resolution, but the inches per pixel that matters. So This script keeps the pixel dimension the same and just changes the resolution to match the ppi, so no quality is lost in placing the new image. However, on line 27, the Math.max and Math.min are reversed. If you want it to fit within the confines of the existing SO, then you have to use Math.max. If you want it to fill the existing SO, then you have to use Math.min.
#target photos
...
Copy link to clipboard
Copied
Off hand, I would say, open the smart object, get the bounds of the actual smart object document. Then size the replacement to fit the SO. It would be slower than just replacing the SO contents, but it shouldn't cause issues with the size.
Copy link to clipboard
Copied
Thank you for the suggestion. How would I get the script to resize the file before placing it into the smart object layer? Given that there's only a reference to a file passed to the replaceContents function.
Copy link to clipboard
Copied
I've been playing around with this, and I came up with a script that would size the new file to fit the current smart object's original size. However, I seemed to have come across a bug where the size is changed, even when the two files are the same size.
You can try it. It was working on older versions of PS, but not the current one. You need to have the smart object selected that you want the content replaced. Then run the script. It will ask for a file.
#target photoshop
app.preferences.rulerUnits = Units.PIXELS;
var doc = activeDocument;
var soLayer = doc.activeLayer;
if (soLayer.kind == LayerKind.SMARTOBJECT){
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID( "Lyr " ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
var obj = executeActionGet(ref).getObjectValue(stringIDToTypeID("smartObjectMore"));
var soSize = obj.getObjectValue(stringIDToTypeID("size"));
var soWidth = soSize.getDouble(stringIDToTypeID("width"));
var soHeight = soSize.getDouble(stringIDToTypeID("height"));
var scrDocFile = File.openDialog ('Select file to \nto replace Smart Object content','*.*',false);
var scrDoc = open(scrDocFile)
app.preferences.rulerUnits = Units.PIXELS;
//var scrDoc = app.documents[1];
scrWidth = scrDoc.width.value;
scrHeight = scrDoc.height.value;
var widthRatio = soWidth/scrWidth
var heightRatio = soHeight/scrHeight
var useRatio = Math.min(widthRatio, heightRatio)
app.activeDocument = scrDoc
scrDoc.resizeImage (scrWidth*useRatio, undefined, undefined, ResampleMethod.BICUBICAUTOMATIC)
scrDoc.saveAs (new File('~/desktop/tempSO.psd'))
var temp_SO = new File('~/desktop/tempSO.psd');
scrDoc.close(SaveOptions.DONOTSAVECHANGES);
replaceSO (temp_SO);
temp_SO.remove();
}
else{alert ('The current layer is not a Smart Object.')}
function replaceSO(file){
var idplacedLayerReplaceContents = stringIDToTypeID( "placedLayerReplaceContents" );
var desc866 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
desc866.putPath( idnull, new File( file ) );
executeAction( idplacedLayerReplaceContents, desc866, DialogModes.NO );
}
Copy link to clipboard
Copied
I figured out the issue with the size. You have to specify the same resolution, as well as the pixel dimension for the smart object and the replacement file. They have to match. Here's a script that should replace a smart object and not change the size. The only size changing will be if the two files don't have the same aspect ration. On line 22 of the code, you can change the bit that says Math.min to Math.max. Math.min will make the new file fit inside the old SO, so one length might be undersized. With Math.max, the new file will fill the old SO and extend out if the aspec ration is not the same.
#target photoshop
app.preferences.rulerUnits = Units.PIXELS;
var doc = activeDocument;
var soLayer = doc.activeLayer;
if (soLayer.kind == LayerKind.SMARTOBJECT){
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID( "Lyr " ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
var obj = executeActionGet(ref).getObjectValue(stringIDToTypeID("smartObjectMore"));
var soSize = obj.getObjectValue(stringIDToTypeID("size"));
var soWidth = soSize.getDouble(stringIDToTypeID("width"));
var soHeight = soSize.getDouble(stringIDToTypeID("height"));
var res = obj.getDouble(charIDToTypeID("Rslt"));
var scrDocFile = File.openDialog ('Select file to \nto replace Smart Object content','*.*',false);
var scrDoc = open(scrDocFile)
app.preferences.rulerUnits = Units.PIXELS;
//var scrDoc = app.documents[1];
scrWidth = scrDoc.width.value;
scrHeight = scrDoc.height.value;
var widthRatio = soWidth/scrWidth
var heightRatio = soHeight/scrHeight
var useRatio = Math.min(widthRatio, heightRatio)
app.activeDocument = scrDoc
scrDoc.resizeImage (scrWidth*useRatio, undefined, res, ResampleMethod.BICUBICAUTOMATIC)
scrDoc.saveAs (new File('~/desktop/tempSO.psd'))
var temp_SO = new File('~/desktop/tempSO.psd');
scrDoc.close(SaveOptions.DONOTSAVECHANGES);
replaceSO (temp_SO);
temp_SO.remove();
}
else{alert ('The current layer is not a Smart Object.')}
function replaceSO(file){
var idplacedLayerReplaceContents = stringIDToTypeID( "placedLayerReplaceContents" );
var desc866 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
desc866.putPath( idnull, new File( file ) );
executeAction( idplacedLayerReplaceContents, desc866, DialogModes.NO );
}
function openSO(){
var idplacedLayerEditContents = stringIDToTypeID( "placedLayerEditContents" );
var desc9 = new ActionDescriptor();
executeAction( idplacedLayerEditContents, desc9, DialogModes.NO );
}
Copy link to clipboard
Copied
I was able to collect the smart object canvas size using the approach below, this function has to be invoked when `
function calculateSmartObjectSize() {
const ref = new ActionReference();
const idLyr = charIDToTypeID("Lyr ");
const idOrdn = charIDToTypeID("Ordn");
const idTrgt = charIDToTypeID("Trgt");
ref.putEnumerated(idLyr, idOrdn, idTrgt);
const idSOMore = stringIDToTypeID("smartObjectMore");
const obj = executeActionGet(ref).getObjectValue(idSOMore);
const idSize = stringIDToTypeID("size");
const _tmp = obj.getObjectValue(idSize);
const idWidth = stringIDToTypeID("width");
const idHeight = stringIDToTypeID("height");
const size = {
width: _tmp.getDouble(idWidth),
height: _tmp.getDouble(idHeight),
};
return size;
}
Copy link to clipboard
Copied
Haven't you noticed the same solution was given earlier by Chuck Uebele?
Copy link to clipboard
Copied
I made some refinements. I found that it wasn't so much the resolution, but the inches per pixel that matters. So This script keeps the pixel dimension the same and just changes the resolution to match the ppi, so no quality is lost in placing the new image. However, on line 27, the Math.max and Math.min are reversed. If you want it to fit within the confines of the existing SO, then you have to use Math.max. If you want it to fill the existing SO, then you have to use Math.min.
#target photoshop
app.preferences.rulerUnits = Units.PIXELS;
var doc = activeDocument;
var soLayer = doc.activeLayer;
if (soLayer.kind == LayerKind.SMARTOBJECT){
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID( "Lyr " ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
var obj = executeActionGet(ref).getObjectValue(stringIDToTypeID("smartObjectMore"));
var soSize = obj.getObjectValue(stringIDToTypeID("size"));
var soWidth = soSize.getDouble(stringIDToTypeID("width"));
var soHeight = soSize.getDouble(stringIDToTypeID("height"));
var res = obj.getDouble(charIDToTypeID("Rslt"));
var scrDocFile = File.openDialog ('Select file to \nto replace Smart Object content','*.*',false);
var scrDoc = open(scrDocFile)
app.preferences.rulerUnits = Units.PIXELS;
scrWidth = scrDoc.width.value;
scrHeight = scrDoc.height.value;
var widthRatio = soWidth/scrWidth
var heightRatio = soHeight/scrHeight
var widthIn = soWidth/res
var heightIn = soHeight/res
app.activeDocument = scrDoc
var resUse = Math.max(scrWidth/widthIn,scrHeight/heightIn)
scrDoc.resizeImage (undefined, undefined, resUse, ResampleMethod.NONE )
scrDoc.saveAs (new File('~/desktop/tempSO.psd'))
var temp_SO = new File('~/desktop/tempSO.psd');
scrDoc.close(SaveOptions.DONOTSAVECHANGES);
replaceSO (temp_SO);
temp_SO.remove();
}
else{alert ('The current layer is not a Smart Object.')}
function replaceSO(file){
var idplacedLayerReplaceContents = stringIDToTypeID( "placedLayerReplaceContents" );
var desc866 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
desc866.putPath( idnull, new File( file ) );
executeAction( idplacedLayerReplaceContents, desc866, DialogModes.NO );
}
function openSO(){
var idplacedLayerEditContents = stringIDToTypeID( "placedLayerEditContents" );
var desc9 = new ActionDescriptor();
executeAction( idplacedLayerEditContents, desc9, DialogModes.NO );
}