Skip to main content
Known Participant
October 14, 2023
Answered

How do I automatically create a shape frame around an image?

  • October 14, 2023
  • 2 replies
  • 7031 views

I do a process where I place rectangular shapes around certain images, these images are always four-sided, usually squares or rectangles, but they are always different, so I keep having to make a new frame around it every time.

The reason why I can't just have the frame made beforehand and just resize it to the new image is because I need the frame to maintain its original ratio, that being, its height in the horizontal parts and its width in the vertical part, the frame needs to keep the same border size and resizing would change that.
My document has a folder containing the separate rectangular shapes that I use to make new shapes each time.

The lenght of the frame should be a full white 43px rectangular. And later when I merge all the rectangles to form the full frame and I also add a black shape stroke of 10px. This stroke is the one found in the shape menu instead of the layer style stroke as they produce different results.

I'm wondering if it's possible to create a script that does the following:
> Create four 43px sized white shape squares.
> Resposition them to be on the 4 borders of the layer that was selected beforehand.

> Resize all of them to have the respective same size as the borders of the original layer they are supposed to be on.

> Merge them all together in one single shape.

> Add a black shape stroke of 10px. (Not to be confused with the Layer Style Stroke)
>Finish with the Frame above the image on the Layers visibility Panel.

This topic has been closed for replies.
Correct answer Stephen Marsh

@HeyoThere – Try this script:

 

/*
Create Frame Around Layer Image.jsx
v1.1 - 15th October 2023, Stephen Marsh
https://community.adobe.com/t5/photoshop-ecosystem-discussions/how-do-i-automatically-create-a-shape-frame-around-an-image/td-p/14157861
Info: This script will add a layer group and a black/white/black frame around the target layer
*/

var origRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
var layerBounds = activeDocument.activeLayer.bounds;

makeGroupFromLayers(activeDocument.activeLayer.name + " Frame");

makeRectangleShapeLayer(0, 0, 0, true, false, 53, 0, 0, 0);
activeDocument.activeLayer.name = "Black Double Stroke Frame"

makeRectangleShapeLayer(0, 0, 0, true, false, 33, 255, 255, 255);
activeDocument.activeLayer.name = "White Fill Frame"

app.preferences.rulerUnits = origRulerUnits;


///// FUNCTIONS /////

function makeRectangleShapeLayer(fillR, fillG, fillB, strokeEnabled, fillEnabled, strokeValue, strokeR, strokeG, strokeB) {
    var idmake = stringIDToTypeID( "make" );
    var desc238 = new ActionDescriptor();
    var idnull = stringIDToTypeID( "null" );
        var ref28 = new ActionReference();
        var idcontentLayer = stringIDToTypeID( "contentLayer" );
        ref28.putClass( idcontentLayer );
    desc238.putReference( idnull, ref28 );
    var idusing = stringIDToTypeID( "using" );
        var desc239 = new ActionDescriptor();
        var idtype = stringIDToTypeID( "type" );
            var desc240 = new ActionDescriptor();
            var idcolor = stringIDToTypeID( "color" );
                var desc241 = new ActionDescriptor();
                var idred = stringIDToTypeID( "red" );
                desc241.putDouble( idred, fillR );
                var idgrain = stringIDToTypeID( "grain" );
                desc241.putDouble( idgrain, fillG );
                var idblue = stringIDToTypeID( "blue" );
                desc241.putDouble( idblue, fillB );
            var idRGBColor = stringIDToTypeID( "RGBColor" );
            desc240.putObject( idcolor, idRGBColor, desc241 );
        var idsolidColorLayer = stringIDToTypeID( "solidColorLayer" );
        desc239.putObject( idtype, idsolidColorLayer, desc240 );
        var idshape = stringIDToTypeID( "shape" );
            var desc242 = new ActionDescriptor();
            var idunitValueQuadVersion = stringIDToTypeID( "unitValueQuadVersion" );
            desc242.putInteger( idunitValueQuadVersion, 1 );
            var idtop = stringIDToTypeID( "top" );
            var idpixelsUnit = stringIDToTypeID( "pixelsUnit" );
            desc242.putUnitDouble( idtop, idpixelsUnit, layerBounds[1].value );
            var idleft = stringIDToTypeID( "left" );
            var idpixelsUnit = stringIDToTypeID( "pixelsUnit" );
            desc242.putUnitDouble( idleft, idpixelsUnit, layerBounds[0].value );
            var idbottom = stringIDToTypeID( "bottom" );
            var idpixelsUnit = stringIDToTypeID( "pixelsUnit" );
            desc242.putUnitDouble( idbottom, idpixelsUnit, layerBounds[3].value );
            var idright = stringIDToTypeID( "right" );
            var idpixelsUnit = stringIDToTypeID( "pixelsUnit" );
            desc242.putUnitDouble( idright, idpixelsUnit, layerBounds[2].value );
            var idtopRight = stringIDToTypeID( "topRight" );
            var idpixelsUnit = stringIDToTypeID( "pixelsUnit" );
            desc242.putUnitDouble( idtopRight, idpixelsUnit, 0.000000 );
            var idtopLeft = stringIDToTypeID( "topLeft" );
            var idpixelsUnit = stringIDToTypeID( "pixelsUnit" );
            desc242.putUnitDouble( idtopLeft, idpixelsUnit, 0.000000 );
            var idbottomLeft = stringIDToTypeID( "bottomLeft" );
            var idpixelsUnit = stringIDToTypeID( "pixelsUnit" );
            desc242.putUnitDouble( idbottomLeft, idpixelsUnit, 0.000000 );
            var idbottomRight = stringIDToTypeID( "bottomRight" );
            var idpixelsUnit = stringIDToTypeID( "pixelsUnit" );
            desc242.putUnitDouble( idbottomRight, idpixelsUnit, 0.000000 );
        var idrectangle = stringIDToTypeID( "rectangle" );
        desc239.putObject( idshape, idrectangle, desc242 );
        var idstrokeStyle = stringIDToTypeID( "strokeStyle" );
            var desc243 = new ActionDescriptor();
            var idstrokeStyleVersion = stringIDToTypeID( "strokeStyleVersion" );
            desc243.putInteger( idstrokeStyleVersion, 2 );
            var idstrokeEnabled = stringIDToTypeID( "strokeEnabled" );
            desc243.putBoolean( idstrokeEnabled, strokeEnabled );
            var idfillEnabled = stringIDToTypeID( "fillEnabled" );
            desc243.putBoolean( idfillEnabled, fillEnabled );
            var idstrokeStyleLineWidth = stringIDToTypeID( "strokeStyleLineWidth" );
            var idpixelsUnit = stringIDToTypeID( "pixelsUnit" );
            desc243.putUnitDouble( idstrokeStyleLineWidth, idpixelsUnit, strokeValue );
            var idstrokeStyleLineDashOffset = stringIDToTypeID( "strokeStyleLineDashOffset" );
            var idpointsUnit = stringIDToTypeID( "pointsUnit" );
            desc243.putUnitDouble( idstrokeStyleLineDashOffset, idpointsUnit, 0.000000 );
            var idstrokeStyleMiterLimit = stringIDToTypeID( "strokeStyleMiterLimit" );
            desc243.putDouble( idstrokeStyleMiterLimit, 100.000000 );
            var idstrokeStyleLineCapType = stringIDToTypeID( "strokeStyleLineCapType" );
            var idstrokeStyleLineCapType = stringIDToTypeID( "strokeStyleLineCapType" );
            var idstrokeStyleButtCap = stringIDToTypeID( "strokeStyleButtCap" );
            desc243.putEnumerated( idstrokeStyleLineCapType, idstrokeStyleLineCapType, idstrokeStyleButtCap );
            var idstrokeStyleLineJoinType = stringIDToTypeID( "strokeStyleLineJoinType" );
            var idstrokeStyleLineJoinType = stringIDToTypeID( "strokeStyleLineJoinType" );
            var idstrokeStyleMiterJoin = stringIDToTypeID( "strokeStyleMiterJoin" );
            desc243.putEnumerated( idstrokeStyleLineJoinType, idstrokeStyleLineJoinType, idstrokeStyleMiterJoin );
            var idstrokeStyleLineAlignment = stringIDToTypeID( "strokeStyleLineAlignment" );
            var idstrokeStyleLineAlignment = stringIDToTypeID( "strokeStyleLineAlignment" );
            var idstrokeStyleAlignCenter = stringIDToTypeID( "strokeStyleAlignCenter" );
            desc243.putEnumerated( idstrokeStyleLineAlignment, idstrokeStyleLineAlignment, idstrokeStyleAlignCenter );
            var idstrokeStyleScaleLock = stringIDToTypeID( "strokeStyleScaleLock" );
            desc243.putBoolean( idstrokeStyleScaleLock, false );
            var idstrokeStyleStrokeAdjust = stringIDToTypeID( "strokeStyleStrokeAdjust" );
            desc243.putBoolean( idstrokeStyleStrokeAdjust, false );
            var idstrokeStyleLineDashSet = stringIDToTypeID( "strokeStyleLineDashSet" );
                var list7 = new ActionList();
            desc243.putList( idstrokeStyleLineDashSet, list7 );
            var idstrokeStyleBlendMode = stringIDToTypeID( "strokeStyleBlendMode" );
            var idblendMode = stringIDToTypeID( "blendMode" );
            var idnormal = stringIDToTypeID( "normal" );
            desc243.putEnumerated( idstrokeStyleBlendMode, idblendMode, idnormal );
            var idstrokeStyleOpacity = stringIDToTypeID( "strokeStyleOpacity" );
            var idpercentUnit = stringIDToTypeID( "percentUnit" );
            desc243.putUnitDouble( idstrokeStyleOpacity, idpercentUnit, 100.000000 );
            var idstrokeStyleContent = stringIDToTypeID( "strokeStyleContent" );
                var desc244 = new ActionDescriptor();
                var idcolor = stringIDToTypeID( "color" );
                    var desc245 = new ActionDescriptor();
                    var idred = stringIDToTypeID( "red" );
                    desc245.putDouble( idred, strokeR );
                    var idgrain = stringIDToTypeID( "grain" );
                    desc245.putDouble( idgrain, strokeG );
                    var idblue = stringIDToTypeID( "blue" );
                    desc245.putDouble( idblue, strokeB );
                var idRGBColor = stringIDToTypeID( "RGBColor" );
                desc244.putObject( idcolor, idRGBColor, desc245 );
            var idsolidColorLayer = stringIDToTypeID( "solidColorLayer" );
            desc243.putObject( idstrokeStyleContent, idsolidColorLayer, desc244 );
            var idstrokeStyleResolution = stringIDToTypeID( "strokeStyleResolution" );
            desc243.putDouble( idstrokeStyleResolution, 72.000000 );
        var idstrokeStyle = stringIDToTypeID( "strokeStyle" );
        desc239.putObject( idstrokeStyle, idstrokeStyle, desc243 );
    var idcontentLayer = stringIDToTypeID( "contentLayer" );
    desc238.putObject( idusing, idcontentLayer, desc239 );
executeAction( idmake, desc238, DialogModes.NO );
}

function makeGroupFromLayers(theName) {
	function s2t(s) {
        return app.stringIDToTypeID(s);
    }
	var descriptor = new ActionDescriptor();
	var descriptor2 = new ActionDescriptor();
	var reference = new ActionReference();
	var reference2 = new ActionReference();
	reference.putClass( s2t( "layerSection" ));
	descriptor.putReference( s2t( "null" ), reference );
	reference2.putEnumerated( s2t( "layer" ), s2t( "ordinal" ), s2t( "targetEnum" ));
	descriptor.putReference( s2t( "from" ), reference2 );
	descriptor2.putString( s2t( "name" ), theName );
	descriptor.putObject( s2t( "using" ), s2t( "layerSection" ), descriptor2 );
	executeAction( s2t( "make" ), descriptor, DialogModes.NO );
}

 

https://prepression.blogspot.com/2017/11/downloading-and-installing-adobe-scripts.html

2 replies

Stephen Marsh
Stephen MarshCorrect answer
Community Expert
October 15, 2023

@HeyoThere – Try this script:

 

/*
Create Frame Around Layer Image.jsx
v1.1 - 15th October 2023, Stephen Marsh
https://community.adobe.com/t5/photoshop-ecosystem-discussions/how-do-i-automatically-create-a-shape-frame-around-an-image/td-p/14157861
Info: This script will add a layer group and a black/white/black frame around the target layer
*/

var origRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
var layerBounds = activeDocument.activeLayer.bounds;

makeGroupFromLayers(activeDocument.activeLayer.name + " Frame");

makeRectangleShapeLayer(0, 0, 0, true, false, 53, 0, 0, 0);
activeDocument.activeLayer.name = "Black Double Stroke Frame"

makeRectangleShapeLayer(0, 0, 0, true, false, 33, 255, 255, 255);
activeDocument.activeLayer.name = "White Fill Frame"

app.preferences.rulerUnits = origRulerUnits;


///// FUNCTIONS /////

function makeRectangleShapeLayer(fillR, fillG, fillB, strokeEnabled, fillEnabled, strokeValue, strokeR, strokeG, strokeB) {
    var idmake = stringIDToTypeID( "make" );
    var desc238 = new ActionDescriptor();
    var idnull = stringIDToTypeID( "null" );
        var ref28 = new ActionReference();
        var idcontentLayer = stringIDToTypeID( "contentLayer" );
        ref28.putClass( idcontentLayer );
    desc238.putReference( idnull, ref28 );
    var idusing = stringIDToTypeID( "using" );
        var desc239 = new ActionDescriptor();
        var idtype = stringIDToTypeID( "type" );
            var desc240 = new ActionDescriptor();
            var idcolor = stringIDToTypeID( "color" );
                var desc241 = new ActionDescriptor();
                var idred = stringIDToTypeID( "red" );
                desc241.putDouble( idred, fillR );
                var idgrain = stringIDToTypeID( "grain" );
                desc241.putDouble( idgrain, fillG );
                var idblue = stringIDToTypeID( "blue" );
                desc241.putDouble( idblue, fillB );
            var idRGBColor = stringIDToTypeID( "RGBColor" );
            desc240.putObject( idcolor, idRGBColor, desc241 );
        var idsolidColorLayer = stringIDToTypeID( "solidColorLayer" );
        desc239.putObject( idtype, idsolidColorLayer, desc240 );
        var idshape = stringIDToTypeID( "shape" );
            var desc242 = new ActionDescriptor();
            var idunitValueQuadVersion = stringIDToTypeID( "unitValueQuadVersion" );
            desc242.putInteger( idunitValueQuadVersion, 1 );
            var idtop = stringIDToTypeID( "top" );
            var idpixelsUnit = stringIDToTypeID( "pixelsUnit" );
            desc242.putUnitDouble( idtop, idpixelsUnit, layerBounds[1].value );
            var idleft = stringIDToTypeID( "left" );
            var idpixelsUnit = stringIDToTypeID( "pixelsUnit" );
            desc242.putUnitDouble( idleft, idpixelsUnit, layerBounds[0].value );
            var idbottom = stringIDToTypeID( "bottom" );
            var idpixelsUnit = stringIDToTypeID( "pixelsUnit" );
            desc242.putUnitDouble( idbottom, idpixelsUnit, layerBounds[3].value );
            var idright = stringIDToTypeID( "right" );
            var idpixelsUnit = stringIDToTypeID( "pixelsUnit" );
            desc242.putUnitDouble( idright, idpixelsUnit, layerBounds[2].value );
            var idtopRight = stringIDToTypeID( "topRight" );
            var idpixelsUnit = stringIDToTypeID( "pixelsUnit" );
            desc242.putUnitDouble( idtopRight, idpixelsUnit, 0.000000 );
            var idtopLeft = stringIDToTypeID( "topLeft" );
            var idpixelsUnit = stringIDToTypeID( "pixelsUnit" );
            desc242.putUnitDouble( idtopLeft, idpixelsUnit, 0.000000 );
            var idbottomLeft = stringIDToTypeID( "bottomLeft" );
            var idpixelsUnit = stringIDToTypeID( "pixelsUnit" );
            desc242.putUnitDouble( idbottomLeft, idpixelsUnit, 0.000000 );
            var idbottomRight = stringIDToTypeID( "bottomRight" );
            var idpixelsUnit = stringIDToTypeID( "pixelsUnit" );
            desc242.putUnitDouble( idbottomRight, idpixelsUnit, 0.000000 );
        var idrectangle = stringIDToTypeID( "rectangle" );
        desc239.putObject( idshape, idrectangle, desc242 );
        var idstrokeStyle = stringIDToTypeID( "strokeStyle" );
            var desc243 = new ActionDescriptor();
            var idstrokeStyleVersion = stringIDToTypeID( "strokeStyleVersion" );
            desc243.putInteger( idstrokeStyleVersion, 2 );
            var idstrokeEnabled = stringIDToTypeID( "strokeEnabled" );
            desc243.putBoolean( idstrokeEnabled, strokeEnabled );
            var idfillEnabled = stringIDToTypeID( "fillEnabled" );
            desc243.putBoolean( idfillEnabled, fillEnabled );
            var idstrokeStyleLineWidth = stringIDToTypeID( "strokeStyleLineWidth" );
            var idpixelsUnit = stringIDToTypeID( "pixelsUnit" );
            desc243.putUnitDouble( idstrokeStyleLineWidth, idpixelsUnit, strokeValue );
            var idstrokeStyleLineDashOffset = stringIDToTypeID( "strokeStyleLineDashOffset" );
            var idpointsUnit = stringIDToTypeID( "pointsUnit" );
            desc243.putUnitDouble( idstrokeStyleLineDashOffset, idpointsUnit, 0.000000 );
            var idstrokeStyleMiterLimit = stringIDToTypeID( "strokeStyleMiterLimit" );
            desc243.putDouble( idstrokeStyleMiterLimit, 100.000000 );
            var idstrokeStyleLineCapType = stringIDToTypeID( "strokeStyleLineCapType" );
            var idstrokeStyleLineCapType = stringIDToTypeID( "strokeStyleLineCapType" );
            var idstrokeStyleButtCap = stringIDToTypeID( "strokeStyleButtCap" );
            desc243.putEnumerated( idstrokeStyleLineCapType, idstrokeStyleLineCapType, idstrokeStyleButtCap );
            var idstrokeStyleLineJoinType = stringIDToTypeID( "strokeStyleLineJoinType" );
            var idstrokeStyleLineJoinType = stringIDToTypeID( "strokeStyleLineJoinType" );
            var idstrokeStyleMiterJoin = stringIDToTypeID( "strokeStyleMiterJoin" );
            desc243.putEnumerated( idstrokeStyleLineJoinType, idstrokeStyleLineJoinType, idstrokeStyleMiterJoin );
            var idstrokeStyleLineAlignment = stringIDToTypeID( "strokeStyleLineAlignment" );
            var idstrokeStyleLineAlignment = stringIDToTypeID( "strokeStyleLineAlignment" );
            var idstrokeStyleAlignCenter = stringIDToTypeID( "strokeStyleAlignCenter" );
            desc243.putEnumerated( idstrokeStyleLineAlignment, idstrokeStyleLineAlignment, idstrokeStyleAlignCenter );
            var idstrokeStyleScaleLock = stringIDToTypeID( "strokeStyleScaleLock" );
            desc243.putBoolean( idstrokeStyleScaleLock, false );
            var idstrokeStyleStrokeAdjust = stringIDToTypeID( "strokeStyleStrokeAdjust" );
            desc243.putBoolean( idstrokeStyleStrokeAdjust, false );
            var idstrokeStyleLineDashSet = stringIDToTypeID( "strokeStyleLineDashSet" );
                var list7 = new ActionList();
            desc243.putList( idstrokeStyleLineDashSet, list7 );
            var idstrokeStyleBlendMode = stringIDToTypeID( "strokeStyleBlendMode" );
            var idblendMode = stringIDToTypeID( "blendMode" );
            var idnormal = stringIDToTypeID( "normal" );
            desc243.putEnumerated( idstrokeStyleBlendMode, idblendMode, idnormal );
            var idstrokeStyleOpacity = stringIDToTypeID( "strokeStyleOpacity" );
            var idpercentUnit = stringIDToTypeID( "percentUnit" );
            desc243.putUnitDouble( idstrokeStyleOpacity, idpercentUnit, 100.000000 );
            var idstrokeStyleContent = stringIDToTypeID( "strokeStyleContent" );
                var desc244 = new ActionDescriptor();
                var idcolor = stringIDToTypeID( "color" );
                    var desc245 = new ActionDescriptor();
                    var idred = stringIDToTypeID( "red" );
                    desc245.putDouble( idred, strokeR );
                    var idgrain = stringIDToTypeID( "grain" );
                    desc245.putDouble( idgrain, strokeG );
                    var idblue = stringIDToTypeID( "blue" );
                    desc245.putDouble( idblue, strokeB );
                var idRGBColor = stringIDToTypeID( "RGBColor" );
                desc244.putObject( idcolor, idRGBColor, desc245 );
            var idsolidColorLayer = stringIDToTypeID( "solidColorLayer" );
            desc243.putObject( idstrokeStyleContent, idsolidColorLayer, desc244 );
            var idstrokeStyleResolution = stringIDToTypeID( "strokeStyleResolution" );
            desc243.putDouble( idstrokeStyleResolution, 72.000000 );
        var idstrokeStyle = stringIDToTypeID( "strokeStyle" );
        desc239.putObject( idstrokeStyle, idstrokeStyle, desc243 );
    var idcontentLayer = stringIDToTypeID( "contentLayer" );
    desc238.putObject( idusing, idcontentLayer, desc239 );
executeAction( idmake, desc238, DialogModes.NO );
}

function makeGroupFromLayers(theName) {
	function s2t(s) {
        return app.stringIDToTypeID(s);
    }
	var descriptor = new ActionDescriptor();
	var descriptor2 = new ActionDescriptor();
	var reference = new ActionReference();
	var reference2 = new ActionReference();
	reference.putClass( s2t( "layerSection" ));
	descriptor.putReference( s2t( "null" ), reference );
	reference2.putEnumerated( s2t( "layer" ), s2t( "ordinal" ), s2t( "targetEnum" ));
	descriptor.putReference( s2t( "from" ), reference2 );
	descriptor2.putString( s2t( "name" ), theName );
	descriptor.putObject( s2t( "using" ), s2t( "layerSection" ), descriptor2 );
	executeAction( s2t( "make" ), descriptor, DialogModes.NO );
}

 

https://prepression.blogspot.com/2017/11/downloading-and-installing-adobe-scripts.html

HeyoThereAuthor
Known Participant
October 15, 2023

The script is working really well, it does exactly what I had envisioned. Upon a few tests I noticed that the end result is a frame with a length of 36px, my frames always end up with a length of 53px, considering the stroke. I tried taking a look at the code to see if it was easy to control the end result of the frame and couldn't find any easy way to control it.

Is it possible to make the final length 53px instead of 36 and furthermore, is it possible to make a way to control this end result in case there's ever a necessity to change it? An easy to modify variable of both the white part and the black outline? Aside from that the code is pretty much what I wanted.

Stephen Marsh
Community Expert
October 15, 2023

The upper frame is your original sample, the lower image at 50% opacity is the result of the script:

 

 

The black stroke value is 35:

 

makeRectangleShapeLayer(0, 0, 0, true, false, 35, 0, 0, 0);

 

 

The white value is 22:

 

makeRectangleShapeLayer(0, 0, 0, true, false, 22, 255, 255, 255);

 

 

EDIT: OK, I can see the difference in your later example file "All Operations.psd"... I'll need to see what is possible.

 

Stephen Marsh
Community Expert
October 14, 2023

You should be able to do this via an action. Is this for single image/layer files? Is the layer bounds always smaller than the canvas size? Or will the layer/image sometimes be the same size as the canvas and flattened?

 

To be crystal clear, please upload before and after layered PSD files.

HeyoThereAuthor
Known Participant
October 14, 2023

> Is this for single image/layer files?
The file should have multiple layers, but the frame should added to one layer per time, I may do it more than one time per file though, not sure if it's an issue.

> Is the layer bounds always smaller than the canvas size?
Yes, always smaller than the canvas.

Can an action resize shapes to different sizes each time? I'm sending an example, but the problem is that the rectangle should be different every time, could even be a square. If an action can do that it's perfect for me. If so I may need to learn how to set up such an action to resize the image like that.

I'm sending one file with all the operations I described on my first comment with one blank layer describing what's being done.

Stephen Marsh
Community Expert
October 14, 2023

While you were replying I was working on a proposal. Please review the attached, which would likely require scripting and not an action. It isn't pixel-perfect, but I feel it is close enough and hopefully suitable for scripting.