/* * File: CreateRoundedRect_0_1.jsx * Author: Peter Torpey * www.petertorpey.com * Version: 0.1 02-01-05 * Original code Copyright 2005 Peter Torpey. * This code may be used, distributed, and modified for personal * use provided the name and URL of the original author, above, * remain intact. * * If this code is used in the creation of a notable production, * please let the author know. The author's e-mail address may be * found at http://www.petertorpey.com/contact.html . * * Host: Adobe After Effects Professional 6.5 * * * Dependencies: * (lib)/UILayout_13.jsx * * * Installation: * Place this file in After Effects' "Script" folder or a subfolder. * On Windows, the default location is: * C:\Program Files\Adobe\After Effects 6.5\Support Files\Scripts\ * * Description: * Creates a mask for the selected layer which is a rounded rectangle. * * * Usage: * Run this script with one or more layers selected to create a mask shape * for each. * * Parameters: * Corner Radius: * Specifies the radius of the corners in pixels or as a percentage * of the width and height. * Rounding: * A percentage value indicating how round the corners should be. * Increasing the rounding value increases the curvature of the * edges. A negative value causes the corners to curve inward. * Lock Height to Width: * When checked, the height value will be the same as the width value * and interpreted as pixels or percentages as the width value. * Width and Height: * These fields define the overall dimension of the rectangle. Values * may be in pixels (eg. 100px) or a percentage of that dimension * of the layer (eg. 30%). * * * Notes: * This script and any scripts upon which it depends have been tested under * AE6.5 on WinXP. * * * Known Issues: * None. * * * For the Future: * Apply to selected keyframes, if any (like ReversePath_0_1). * * */ /*** APPLICATION GLOBALS ***/ { /*** DEFAULTS ***/ var NAME_STR = "Create Rounded Rectangle"; var D_WIDTH_HEIGHT = "300px"; var D_RADIUS = "0px"; var D_ROUNDING = "100%"; var D_LOCK_WIDTH_HEIGHT = true; /*** SCRIPT GLOBALS ***/ var readyState = true; // includes var includeScripts = ["(lib)/UILayout_13.jsx"]; for (var i = 0; i < includeScripts.length; i++) { var scriptFile = new File(includeScripts[i]); if (scriptFile.open()) { eval(scriptFile.read()); scriptFile.close(); } else { readyState = false; alert(NAME_STR + ":\n\nUnable to open included file: \"" + includeScripts[i] + "\"."); } } function parseDistance(str, ref) { var ps = str.match(/(\d*(?:\.\d*)?)\s*(%|px|pix)?/); if (ps) { if (ps[2] && ps[2] == "%") { return parseFloat(str) / 100 * ref; } else { return parseFloat(str); } } return parseFloat(ref); } function buildDialog() { var dlg = new Window("dialog", NAME_STR, [100, 100, 470, 500]); var shpPnl = dlg.addUI("panel", "Corner Properties"); var radField = shpPnl.addUI("labeledittext", " Radius"); radField.text = D_RADIUS; shpPnl.addUI("break"); var rndField = shpPnl.addUI("labeledittext", "Rounding"); rndField.text = D_ROUNDING; var posPnl = dlg.addUI("panel", "Size & Rotation"); var lockCheck = posPnl.addUI("checkbox", "Lock Height to Width"); lockCheck.value = D_LOCK_WIDTH_HEIGHT; var widthField = posPnl.addUI("labeledittext", "Width"); widthField.text = D_WIDTH_HEIGHT; var heightField = posPnl.addUI("labeledittext", "Height"); heightField.enabled = false; heightField.text = D_WIDTH_HEIGHT; dlg.addUI("button", "Cancel", {name: "cancel"}); dlg.addUI("button", "Create Rectangle", {name: "ok"}); // handlers rndField.onChange = function () { var rnd = parseFloat(rndField.text); /* if (!(rnd && (rnd >= -100 && rnd <= 100))) { rnd = 0; alert("The Rounding value must be in the range 0% to 100%."); } */ rndField.text = rnd + "%"; }; widthField.onChange = function () { if (lockCheck.value) { heightField.text = widthField.text; } }; lockCheck.onClick = function () { heightField.enabled = !lockCheck.value; }; // accessors (Yes, I'm using the UI as the model, today...) dlg.getRounding = function () { var rnd = parseFloat(rndField.text); // if (rnd < 0.0) { rnd = 0.0; } // if (rnd > 100.0) { rnd = 100.0; } return (rnd / 100.0); }; dlg.getRadius = function (ref) { var rad = parseDistance(radField.text, ref); if (rad < 0.0) { rad = 0.0; } return rad; }; dlg.getWidth = function (ref) { return parseDistance(widthField.text, ref); }; dlg.getHeight = function (ref) { return parseDistance(heightField.text, ref); }; dlg.getRotation = function () { var rot = parseFloat(rotField.text); if (rot) { while (rot > 360.0) { rot -= 360.0; } while (rot < 0) { rot += 360.0; } return rot; } return 0.0; }; layoutUI(dlg); dlg.center(); return dlg; } function createRect(cX, cY, width, height, radiusW, radiusH, rounding) { var shape = new Shape(); var tVerts = new Array() var tInTans = new Array(); var tOutTans = new Array(); var vert1, vert2, tan1, tan2; var zv = [0, 0]; var doRounding = (radiusW != 0.0) && (radiusH != 0.0); width /= 2.0; height /= 2.0; shape.closed = true; vert1 = [-width, -height + Math.abs(radiusH)]; vert2 = [-width + Math.abs(radiusW), -height]; if (rounding < 0.0) { tan1 = [-radiusW / 2.0 * rounding, 0]; tan2 = [0, -radiusH / 2.0 * rounding]; } else { tan1 = [0, -radiusH / 2.0 * rounding]; tan2 = [-radiusW / 2.0 * rounding, 0]; } // tl tVerts.push([vert1[0] + cX, vert1[1] + cY]); if (doRounding) { tInTans.push(zv); tOutTans.push([tan1[0], tan1[1]]); tVerts.push([vert2[0] + cX, vert2[1] + cY]); tInTans.push([tan2[0], tan2[1]]); tOutTans.push(zv); } else { tInTans.push(zv); tOutTans.push(zv); } // tr tVerts.push([-vert2[0] + cX, vert2[1] + cY]); if (doRounding) { tInTans.push(zv); tOutTans.push([-tan2[0], tan2[1]]); tVerts.push([-vert1[0] + cX, vert1[1] + cY]); tInTans.push([-tan1[0], tan1[1]]); tOutTans.push(zv); } else { tInTans.push(zv); tOutTans.push(zv); } // br tVerts.push([-vert1[0] + cX, -vert1[1] + cY]); if (doRounding) { tInTans.push(zv); tOutTans.push([-tan1[0], -tan1[1]]); tVerts.push([-vert2[0] + cX, -vert2[1] + cY]); tInTans.push([-tan2[0], -tan2[1]]); tOutTans.push(zv); } else { tInTans.push(zv); tOutTans.push(zv); } // bl tVerts.push([vert2[0] + cX, -vert2[1] + cY]); if (doRounding) { tInTans.push(zv); tOutTans.push([tan2[0], -tan2[1]]); tVerts.push([vert1[0] + cX, -vert1[1] + cY]); tInTans.push([tan1[0], -tan1[1]]); tOutTans.push(zv); } shape.vertices = tVerts; shape.inTangents = tInTans; shape.outTangents = tOutTans; return shape; } function main() { if (!readyState) { return -1; } var curItem = app.project.activeItem; if (curItem != null && (curItem instanceof CompItem)) { var curLayers = curItem.selectedLayers; if (curLayers.length > 0) { var curLayer, curMasks, curMask, shape; var w, h; var dialog = buildDialog(); if (dialog.show() == 1) { app.beginUndoGroup(NAME_STR); for (var i = 0; i < curLayers.length; i++) { curLayer = curLayers[i]; w = dialog.getWidth(curLayer.width); h = dialog.getHeight(curLayer.height); shape = createRect(curLayer.anchorPoint.value[0], curLayer.anchorPoint.value[1], w, h, dialog.getRadius(w), dialog.getRadius(h), dialog.getRounding()); curMasks = curLayer.property("ADBE Mask Parade"); if (curMasks && curMasks.canAddProperty("ADBE Mask Atom")) { curMask = curMasks.addProperty("ADBE Mask Atom"); curMask.property("ADBE Mask Shape").setValue(shape); } } app.endUndoGroup(); } } else { alert("Please select a layer on which to apply the created mask shape."); } } else { alert("Please select a layer on which to apply the created mask shape."); } } main(); }