Paste image to fit smart layer

Explorer ,
Mar 27, 2022 Mar 27, 2022

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?

TOPICS
Actions and scripting

Views

163

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Adobe Community Professional , Mar 30, 2022 Mar 30, 2022
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...

Likes

Translate

Translate
Adobe Community Professional ,
Mar 27, 2022 Mar 27, 2022

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.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Mar 27, 2022 Mar 27, 2022

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.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe Community Professional ,
Mar 29, 2022 Mar 29, 2022

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 );
    }

 

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe Community Professional ,
Mar 29, 2022 Mar 29, 2022

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 );
    }

 

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Mar 29, 2022 Mar 29, 2022

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 `

doc.activeLayer` is set to a smart object layer.

 

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;
}

 

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Mar 30, 2022 Mar 30, 2022

Copy link to clipboard

Copied

Haven't you noticed the same solution was given earlier by Chuck Uebele?

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe Community Professional ,
Mar 30, 2022 Mar 30, 2022

Copy link to clipboard

Copied

LATEST

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 );
    }

 

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines