Skip to main content
Known Participant
June 24, 2025
Answered

Resize layer to match key object height or width, whichever is greater

  • June 24, 2025
  • 1 reply
  • 402 views

So I found this simple script:

https://community.adobe.com/t5/illustrator-discussions/illustrator-cc-how-to-manually-resize-one-object-to-match-another/m-p/11057446#M173293

//by Ray Craighead
//Select 2 objects. Script will scale top object to match bottom object.

function scaleTopObject( ){
    var aDoc = app.activeDocument;
    var sel = aDoc.selection;
    var topObj = sel[0];
    var botObj = sel[1];
    topObj.width = botObj.width;
    topObj.height = botObj.height;
    }

if (selection.length == 2) {
  scaleTopObject( );
} else alert ("Select 2 object. Top object will scale to match bottom object.");

 

And that is great, but I'm wondering how to modify it, or if its even possible, to determine if the width or height of the bottom object is greater, then resize the top object using either the width or height, but scaled proportionately?

Is this an over the top idea or possible using percentages?

Thanks!

Correct answer jduncan

Hey, here's an updated version of the script that is a bit more robust and also moves the top object to match the location of the bottom object. You just need to decide where you want the object to align at. There is a settings section at the top of the script where you can change the "anchor alighment". Also note, this script uses geometricBounds to determine the movement. Try it out and let me know what you think?

(function () {
    //@target illustrator

    // script settings

    // where should to top object align to the bottom object when moved
    // options (default is center-center): top-left, top-center, top-right, center-left, center-right, bottom-left, bottom-center, bottom-right, top-edge, bottom-edge, left-edge, right-edge, horizontal-center, vertical-center
    var alignObjectsAt = "center-center";

    // sanity checks

    // no need to continue if there is no active document
    if (!app.documents.length) {
        alert("No active document.");
        return;
    }

    // grab document and selection info
    var doc = app.activeDocument;
    var sel = doc.selection;

    // no need to continue if there is no active selection (or less than 2 objects are selected)
    if (sel.length < 2) {
        alert("No active selection.\nSelect at least two objects.");
        return;
    }

    // 1. first we grab reference to the "top" and "bottom" objects

    // grab the top (0th index) and bottom (1st index) objects (all else ignored)
    var topObject = sel[0];
    var bottomObject = sel[1];

    // 2. next we scale the object to match the bottom object

    // determine greater of width vs. height of bottom object
    // then calculate proportional scale matrix for top object
    var ratio = 100;
    if (bottomObject.width >= bottomObject.height) {
        ratio = (bottomObject.width / (topObject.width || 1)) * 100;
    } else {
        ratio = (bottomObject.height / (topObject.height || 1)) * 100;
    }
    var scaleMatrix = app.getScaleMatrix(ratio, ratio);
    topObject.transform(scaleMatrix, true, false, false, false, false, undefined);

    // 3. finally, we move the top object to match the location of the bottom object
    var moveMatrix = getMoveMatrix(
        bottomObject.geometricBounds,
        topObject.geometricBounds,
        alignObjectsAt
    );
    topObject.transform(
        moveMatrix,
        true, // objects
        true, // patterns
        true, // gradients
        true // stroke patterns
    );

    // helper functions

    /**
     * Extracts geometric information from Illustrator object bounds.
     *
     * @9397041 {Array<number>} bounds - Illustrator object bounds: [left, top, right, bottom].
     * @Returns {{left: number, top: number, right: number, bottom: number, width: number, height: number, centerX: number, centerY: number}} - An object containing geometric details of the bounds.
     */
    function getObjectPlacementInfo(bounds) {
        if (!bounds || typeof bounds !== "object" || bounds.length !== 4) {
            throw new Error("Invalid bounds: Expected [left, top, right, bottom]");
        }

        // Normalize for safety since occasionally Illustrator can return
        // inverted bounds (e.g., top < bottom due to transformations).
        var left = Math.min(bounds[0], bounds[2]);
        var right = Math.max(bounds[0], bounds[2]);
        var top = Math.max(bounds[1], bounds[3]);
        var bottom = Math.min(bounds[1], bounds[3]);

        var width = right - left;
        var height = top - bottom;
        var centerX = left + width / 2;
        var centerY = top - height / 2;

        return {
            left: left,
            top: top,
            right: right,
            bottom: bottom,
            width: width,
            height: height,
            centerX: centerX,
            centerY: centerY,
        };
    }

    /**
     * Creates a translation matrix to align the target object relative to the source object.
     *
     * @9397041 {Array<number>} sourceBounds - Bounds of source object to move to.
     * @9397041 {Array<number>} targetBounds - Bounds of target object to be moved.
     * @9397041 {string} anchor - Alignment of target object in relation to the source object.
     * @Returns {Matrix} - A translation matrix for aligning the target object to the source object.
     */
    function getMoveMatrix(sourceBounds, targetBounds, anchor) {
        anchor = typeof anchor !== "undefined" ? anchor : "center-center";
        var sourceInfo = getObjectPlacementInfo(sourceBounds);
        var targetInfo = getObjectPlacementInfo(targetBounds);

        switch (anchor.toLowerCase()) {
            case "top-left":
                return app.getTranslationMatrix(
                    sourceInfo.left - targetInfo.left,
                    sourceInfo.top - targetInfo.top
                );
            case "top-center":
                return app.getTranslationMatrix(
                    sourceInfo.centerX - targetInfo.centerX,
                    sourceInfo.top - targetInfo.top
                );
            case "top-right":
                return app.getTranslationMatrix(
                    sourceInfo.right - targetInfo.right,
                    sourceInfo.top - targetInfo.top
                );
            case "center-left":
                return app.getTranslationMatrix(
                    sourceInfo.left - targetInfo.left,
                    sourceInfo.centerY - targetInfo.centerY
                );
            case "center-right":
                return app.getTranslationMatrix(
                    sourceInfo.right - targetInfo.right,
                    sourceInfo.centerY - targetInfo.centerY
                );
            case "bottom-left":
                return app.getTranslationMatrix(
                    sourceInfo.left - targetInfo.left,
                    sourceInfo.bottom - targetInfo.bottom
                );
            case "bottom-center":
                return app.getTranslationMatrix(
                    sourceInfo.centerX - targetInfo.centerX,
                    sourceInfo.bottom - targetInfo.bottom
                );
            case "bottom-right":
                return app.getTranslationMatrix(
                    sourceInfo.right - targetInfo.right,
                    sourceInfo.bottom - targetInfo.bottom
                );
            case "top-edge":
                return app.getTranslationMatrix(0, sourceInfo.top - targetInfo.top);
            case "bottom-edge":
                return app.getTranslationMatrix(
                    0,
                    sourceInfo.bottom - targetInfo.bottom
                );
            case "left-edge":
                return app.getTranslationMatrix(sourceInfo.left - targetInfo.left, 0);
            case "right-edge":
                return app.getTranslationMatrix(sourceInfo.right - targetInfo.right, 0);
            case "horizontal-center":
                return app.getTranslationMatrix(
                    sourceInfo.centerX - targetInfo.centerX,
                    0
                );
            case "vertical-center":
                return app.getTranslationMatrix(
                    0,
                    sourceInfo.centerY - targetInfo.centerY
                );
            default:
                // fallback to center alignment
                return app.getTranslationMatrix(
                    sourceInfo.centerX - targetInfo.centerX,
                    sourceInfo.centerY - targetInfo.centerY
                );
        }
    }
})();

1 reply

jduncan
Community Expert
Community Expert
June 24, 2025

Here's a script that will resize the top object proportionally to the larger of the width or height of the bottom object. Try it out and let me know if you have any questions. And if you need more flexibility, take a look at my script MatchObjects.jsx. Cheers!

(function () {
    //@target illustrator

    // no need to continue if there is no active document
    if (!app.documents.length) {
        alert("No active document.");
        return;
    }

    // grab document and selection info
    var doc = app.activeDocument;
    var sel = doc.selection;

    // no need to continue if there is no active selection (or less than 2 objects are selected)
    if (sel.length < 2) {
        alert("No active selection.\nSelect at least two objects.");
        return;
    }

    // grab the top (0th index) and bottom (1st index) objects (all else ignored)
    var topObject = sel[0];
    var bottomObject = sel[1];

    // determine greater of width vs. height of bottom object
    // then calculate proportional scale matrix for top object
    var widthProp, heightProp, scaleMatrix;
    if (bottomObject.width >= bottomObject.height) {
        widthProp = (bottomObject.width / topObject.width) * 100;
        heightProp = (bottomObject.width / topObject.width) * 100;
    } else {
        widthProp = (bottomObject.height / topObject.height) * 100;
        heightProp = (bottomObject.height / topObject.height) * 100;
    }
    scaleMatrix = app.getScaleMatrix(widthProp, heightProp);

    /**
     * docs: https://ai-scripting.docsforadobe.dev/jsobjref/PageItem/#pageitemtransform
     * app.activeDocument.pageItems[index].transform(
     *     transformationMatrix     Transformation matrix to apply
     *     [,changePositions]       Whether to change Positions
     *     [,changeFillPatterns]    Whether to change Fill Patterns
     *     [,changeFillGradients]   Whether to change Fill Gradients
     *     [,changeStrokePattern]   Whether to change Stroke Pattern
     *     [,changeLineWidths]      The amount to scale line widths
     *     [,transformAbout]        The point to use as anchor, to transform about
     * )
     */
    topObject.transform(scaleMatrix, true, false, false, false, false, undefined);
})();

 

Known Participant
June 24, 2025

Thank you! I think that works. I'm going to play around with it with a few different shapes to make sure. I was using your Match Objects script, which is great but I needed to be able to to do it without the prompt so I can use it with batch processing.
If I wanted to also have it align to the bottom object, where would I need to add that?

jduncan
Community Expert
Community Expert
March 18, 2026

@JustMeTrying5564, if I understand what you are asking, the revised script below should clamp the top object within 2.25” of the bottom object. See item `2.5` in the code. Take it for a spin and let me know if this works? Cheers!

/*
MatchTopObjectToBottomV2.jsx for Adobe Illustrator
--------------------------------------------------

Scale the top object proportionally to match the largest dimension (width or height) of the
bottom object of the selection, then move the top object to match the position of the bottom object.

Created in response to this question on the Adobe forum:
https://community.adobe.com/t5/illustrator-discussions/resize-layer-to-match-key-object-height-or-width-whichever-is-greater/td-p/15386148

**V2 Addition** Ensure that the bottom-edge of the newly scaled top-object doesn't get closer than 2.25 inches
from the bottom of the top object. Added from question:
https://community.adobe.com/questions-652/resize-layer-to-match-key-object-height-or-width-whichever-is-greater-816301?postid=7520642#post7520642
*/

(function () {
//@target illustrator

// script settings

// where should to top object align to the bottom object when moved
// options (default is center-center): top-left, top-center, top-right, center-left, center-right, bottom-left, bottom-center, bottom-right, top-edge, bottom-edge, left-edge, right-edge, horizontal-center, vertical-center, top-minus
var alignObjectsAt = "top-minus";

// custom offset amount for top-minus
var customOffset = 162;

// sanity checks

// no need to continue if there is no active document
if (!app.documents.length) {
alert("No active document.");
return;
}

// grab document and selection info
var doc = app.activeDocument;
var sel = doc.selection;

// no need to continue if there is no active selection (or less than 2 objects are selected)
if (sel.length < 2) {
alert("No active selection.\nSelect at least two objects.");
return;
}

// 1. first we grab reference to the "top" and "bottom" objects

// grab the top (0th index) and bottom (1st index) objects (all else ignored)
var topObject = sel[0];
var bottomObject = sel[1];

// 2. next we scale the object to match the bottom object

// determine greater of width vs. height of bottom object
// then calculate proportional scale matrix for top object
var ratio = 100;
if (bottomObject.width >= bottomObject.height) {
ratio = (bottomObject.width / (topObject.width || 1)) * 100;
} else {
ratio = (bottomObject.height / (topObject.height || 1)) * 100;
}
var scaleMatrix = app.getScaleMatrix(ratio, ratio);
topObject.transform(scaleMatrix, true, false, false, false, false, undefined);

// 2.5. check to see if the newly scaled size is within

// this could be done above in one calculation but I am keeping
// it separate so it is very obvious what the script is doing

// https://community.adobe.com/questions-652/resize-layer-to-match-key-object-height-or-width-whichever-is-greater-816301?postid=7520642#post7520642
if (topObject.height > bottomObject.height - customOffset * 2) {
var resizeRatio =
((bottomObject.height - customOffset * 2) / topObject.height) * 100;
var resizeScaleMatrix = app.getScaleMatrix(resizeRatio, resizeRatio);
topObject.transform(
resizeScaleMatrix,
true,
false,
false,
false,
false,
undefined
);
}

// 3. finally, we move the top object to match the location of the bottom object
var moveMatrix = getMoveMatrix(
bottomObject.geometricBounds,
topObject.geometricBounds,
alignObjectsAt
);
topObject.transform(
moveMatrix,
true, // objects
true, // patterns
true, // gradients
true // stroke patterns
);

// helper functions

/**
* Extracts geometric information from Illustrator object bounds.
*
* @param {Array<number>} bounds - Illustrator object bounds: [left, top, right, bottom].
* @returns {{left: number, top: number, right: number, bottom: number, width: number, height: number, centerX: number, centerY: number}} - An object containing geometric details of the bounds.
*/
function getObjectPlacementInfo(bounds) {
if (!bounds || typeof bounds !== "object" || bounds.length !== 4) {
throw new Error("Invalid bounds: Expected [left, top, right, bottom]");
}

// Normalize for safety since occasionally Illustrator can return
// inverted bounds (e.g., top < bottom due to transformations).
var left = Math.min(bounds[0], bounds[2]);
var right = Math.max(bounds[0], bounds[2]);
var top = Math.max(bounds[1], bounds[3]);
var bottom = Math.min(bounds[1], bounds[3]);

var width = right - left;
var height = top - bottom;
var centerX = left + width / 2;
var centerY = top - height / 2;

return {
left: left,
top: top,
right: right,
bottom: bottom,
width: width,
height: height,
centerX: centerX,
centerY: centerY,
};
}

/**
* Creates a translation matrix to align the target object relative to the source object.
*
* @param {Array<number>} sourceBounds - Bounds of source object to move to.
* @param {Array<number>} targetBounds - Bounds of target object to be moved.
* @param {string} anchor - Alignment of target object in relation to the source object.
* @returns {Matrix} - A translation matrix for aligning the target object to the source object.
*/
function getMoveMatrix(sourceBounds, targetBounds, anchor) {
anchor = typeof anchor !== "undefined" ? anchor : "center-center";
var sourceInfo = getObjectPlacementInfo(sourceBounds);
var targetInfo = getObjectPlacementInfo(targetBounds);

switch (anchor.toLowerCase()) {
case "top-left":
return app.getTranslationMatrix(
sourceInfo.left - targetInfo.left,
sourceInfo.top - targetInfo.top
);
case "top-center":
return app.getTranslationMatrix(
sourceInfo.centerX - targetInfo.centerX,
sourceInfo.top - targetInfo.top
);
case "top-right":
return app.getTranslationMatrix(
sourceInfo.right - targetInfo.right,
sourceInfo.top - targetInfo.top
);
case "center-left":
return app.getTranslationMatrix(
sourceInfo.left - targetInfo.left,
sourceInfo.centerY - targetInfo.centerY
);
case "center-right":
return app.getTranslationMatrix(
sourceInfo.right - targetInfo.right,
sourceInfo.centerY - targetInfo.centerY
);
case "bottom-left":
return app.getTranslationMatrix(
sourceInfo.left - targetInfo.left,
sourceInfo.bottom - targetInfo.bottom
);
case "bottom-center":
return app.getTranslationMatrix(
sourceInfo.centerX - targetInfo.centerX,
sourceInfo.bottom - targetInfo.bottom
);
case "bottom-right":
return app.getTranslationMatrix(
sourceInfo.right - targetInfo.right,
sourceInfo.bottom - targetInfo.bottom
);
case "top-edge":
return app.getTranslationMatrix(0, sourceInfo.top - targetInfo.top);
case "bottom-edge":
return app.getTranslationMatrix(
0,
sourceInfo.bottom - targetInfo.bottom
);
case "left-edge":
return app.getTranslationMatrix(sourceInfo.left - targetInfo.left, 0);
case "right-edge":
return app.getTranslationMatrix(sourceInfo.right - targetInfo.right, 0);
case "horizontal-center":
return app.getTranslationMatrix(
sourceInfo.centerX - targetInfo.centerX,
0
);
case "vertical-center":
return app.getTranslationMatrix(
0,
sourceInfo.centerY - targetInfo.centerY
);
case "top-minus":
return app.getTranslationMatrix(
sourceInfo.centerX - targetInfo.centerX,
sourceInfo.top - customOffset - targetInfo.top
);
default:
// fallback to center alignment
return app.getTranslationMatrix(
sourceInfo.centerX - targetInfo.centerX,
sourceInfo.centerY - targetInfo.centerY
);
}
}
})();