Rounded Rectangle Mask via Scripting

Participant ,
Jan 12, 2022 Jan 12, 2022

Copy link to clipboard

Copied

Hey Guys,

 

I am creating a script that applies a round rectangle mask to any layer that is selected. I have written the following code.

 

My question is, how do I make the vertices scale correctly to the size of any given comp? For example the code below has the vertices hard coded for a compostion of 1920x1080. How can I make this dynamic so it would work the same on an 8k comp for example.

 

Thanks,

Liam

 

btnMaskRoudRect.onClick = function() {
    if(app.project.activeItem == undefined || app.project.activeItem == null) {
        alert("Please Select a Composition.");
        return false;
     }
     if(app.project.activeItem.selectedLayers.length < 1) {
         alert("Please Select a Layer.");
     }
 else {
    maskRoudRect(app.project.activeItem.selectedLayers);
     }
     function maskRoudRect() {
        for(var i = 0; i < app.project.activeItem.selectedLayers.length; i++) {
        app.beginUndoGroup("Undo Rounded Rectangle Mask");
        myLayer = app.project.activeItem.selectedLayers[i];
        comp = app.project.activeItem;
        newMask = myLayer.Masks.addProperty("ADBE Mask Atom");
        newMask.maskMode = MaskMode.ADD;
        myProperty = newMask.property("ADBE Mask Shape");
        myShape = myProperty.value;
        myShape.vertices = [[1900, 0],[20, 0],[0, 20],[0, 1060],[20, 1080],[1900, 1080],[1920, 1060],[1920, 20]];
        myShape.inTangents = [[11.045654296875,0],[0,0],[0,-11.457153320312],[0,0],[-11.457153320312,0],[0,0],[0,11.045654296875],[0,0]];
        myShape.outTangents = [[0,0],[-11.457153320312,0],[0,0],[0,11.045654296875],[0,0],[11.045654296875,0],[0,0],[0,-11.457153320312]];
        myShape.closed = true;
        myProperty.setValue(myShape);
        app.endUndoGroup();
    } 
}

 

TOPICS
Scripting

Views

564

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 , Jan 13, 2022 Jan 13, 2022

say a vertex is at [x,y] in a comp with 1920x1080 and you want to scale everything to fit your comp.

Then you can do

var scaleX = comp.width/1920;
var scaleY = comp.height/1080;

scaledVertex = [x*scaleX, y*scaleY]

Likes

Translate

Translate
Adobe Community Professional ,
Jan 13, 2022 Jan 13, 2022

Copy link to clipboard

Copied

Obviously you'd have to retrieve the comp size and insert the values as variables, none of which exists in your current code.

 

Mylenium

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
Participant ,
Jan 13, 2022 Jan 13, 2022

Copy link to clipboard

Copied

Thanks for replying Mylenium.

 

Correct, they don't. I can retrieve those values via comp.width and comp.height.

 

My issue is, once I have these, how do I use this to calculate where the vertices should be in any given comp?

 

Thanks,

Liam

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 ,
Jan 13, 2022 Jan 13, 2022

Copy link to clipboard

Copied

say a vertex is at [x,y] in a comp with 1920x1080 and you want to scale everything to fit your comp.

Then you can do

var scaleX = comp.width/1920;
var scaleY = comp.height/1080;

scaledVertex = [x*scaleX, y*scaleY]

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
Participant ,
Jan 13, 2022 Jan 13, 2022

Copy link to clipboard

Copied

Thanks Mathias and Mylenium, this works well for scaling the vertices.

 

One thing I have noticed is when the vertices are scaled, the bezier handle do not adjust accordingling. Please see attached image. The 1080p image works perfect, the 4k image is lacking that roundness.

 

The value of the in/out tangents doesn't change but the bezier handle does. Why is that? Is that in relation to the bezier forumla or Is this a different property all together?

 

Thanks,

Liam

1080p Comp.png

 

4k Comp.png

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 ,
Jan 14, 2022 Jan 14, 2022

Copy link to clipboard

Copied

You need to scale the inTangents and outTangents, too (using exactly the same formula).
The handles in your 4K comp have exactly the same length as the ones in the HD comp. But since the shape itself is much bigger in the 4K comp, the handles are smaller relatize to the size of the shape itself.

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
Participant ,
Jan 15, 2022 Jan 15, 2022

Copy link to clipboard

Copied

Perfect! Much appreciated Mathias and working well.

 

Thanks,

Liam 

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 ,
Jan 16, 2022 Jan 16, 2022

Copy link to clipboard

Copied

You are welcome 🙂

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
Participant ,
Jan 17, 2022 Jan 17, 2022

Copy link to clipboard

Copied

Apologies Mathias, I do have an additional question if I may.

 

The codes works as intended however I hadn't anticipated for layers to be of a different size to the compistion. The images below show a solid layer that is 5000x5000 with out a mask and then the mask applied (please see code below). How would I compensate for the size of the layer? Would I need to use sourceRectAtTime to find out it's size as opposed to using the comp.widthscaleX, comp.height*scaleY.

 

No Mask.pngMask Applied.png

 

 

btnMaskRoudRect.onClick = function() {
    if(app.project.activeItem == undefined || app.project.activeItem == null) {
        alert("Please Select a Composition");
        return false;
     }
     if(app.project.activeItem.selectedLayers.length < 1) {
         alert("Please Select a Layer");
     }
 else {
    maskRoudRect(app.project.activeItem.selectedLayers);
     }
     function maskRoudRect() {
        for(var i = 0; i < app.project.activeItem.selectedLayers.length; i++) {
        app.beginUndoGroup("Undo Rounded Rectangle Mask");
        myLayer = app.project.activeItem.selectedLayers[i];
        comp = app.project.activeItem;
        newMask = myLayer.Masks.addProperty("ADBE Mask Atom");
        newMask.name = "Rounded Rectangle Mask";
        newMask.maskMode = MaskMode.ADD;
        myProperty = newMask.property("ADBE Mask Shape");
        myShape = myProperty.value;
        var scaleX = comp.width/1920;
        var scaleY = comp.height/1080;
        myShape.vertices = [[1900*scaleX, 0*scaleY],[20*scaleX, 0*scaleY],[0*scaleX, 20*scaleY],[0*scaleX, 1060*scaleY],[20*scaleX, 1080*scaleY],[1900*scaleX, 1080*scaleY],[1920*scaleX, 1060*scaleY],[1920*scaleX, 20*scaleY]];
        myShape.inTangents = [[11.045654296875*scaleX,0*scaleY],[0*scaleX,0*scaleY],[0*scaleX,-11.457153320312*scaleY],[0*scaleX,0*scaleY],[-11.457153320312*scaleX,0*scaleY],[0*scaleX,0*scaleY],[0*scaleX,11.045654296875*scaleY],[0*scaleX,0]*scaleY];
        myShape.outTangents = [[0*scaleX,0*scaleY],[-11.457153320312*scaleX,0*scaleY],[0*scaleX,0*scaleY],[0*scaleX,11.045654296875*scaleY],[0*scaleX,0*scaleY],[11.045654296875*scaleX,0*scaleY],[0*scaleX,0*scaleY],[0*scaleX,-11.457153320312*scaleY]];
        
        myShape.closed = true;
        myProperty.setValue(myShape);
        app.endUndoGroup(); 
    } 
}

 

 

Thanks again!

Liam

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 ,
Jan 19, 2022 Jan 19, 2022

Copy link to clipboard

Copied

AVLayers also have a width and height property:

https://ae-scripting.docsforadobe.dev/layers/avlayer.html#avlayer-width

Hence, you should be able to simply use your layer's width and height instead of the one of the comp.

 

SourceRect is helpful for text and shape layers, since those have the same size as the comp, but their actual content might have a different size (and change over time by keyframing the text or animating shapes).

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
Participant ,
Jan 20, 2022 Jan 20, 2022

Copy link to clipboard

Copied

LATEST

Ah that's great. I had totally overlooked layer.width. Thanks Mathias!

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 ,
Jan 13, 2022 Jan 13, 2022

Copy link to clipboard

Copied

You can simply proportionally scale based on existing info as Mathias suggested, you can implement the actual Bèzier formula or given the cubic nature of the curves just assume that around 33.33 percent tangent length makes for a perfect circle and thus multiply your values with 0.3333 or something. Whatever works best for you.

 

Mylenium

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