Copy link to clipboard
Copied
Hello Everyone!
I need your help with a JavaSrcript that can resize a selected object (frame/image/lineart etc) in a calculated way i.e.
a) Width of the selected object should become equal to the width of the Document/Artboard.
b) Height should become [sqrt(documentWidth * documentHeight) * 0.08]
Thanks in advance.
Masood
app.selection[0].width = app.activeDocument.width;
app.selection[0].height = Math.sqrt(app.activeDocument.width * app.activeDocument.height) * 0.08;
Copy link to clipboard
Copied
app.selection[0].width = app.activeDocument.width;
app.selection[0].height = Math.sqrt(app.activeDocument.width * app.activeDocument.height) * 0.08;
Copy link to clipboard
Copied
Thanks, a lot, very quick, much appreciated.
The code is working fine on empty frames, but not on the ones with clipping masks. Can you please check this.
Copy link to clipboard
Copied
…and
How can I change only one side (height/width) and make the other side reduce/enlarge proportionally. If I'm applying the script on a frame with an image.
Copy link to clipboard
Copied
If you are are familiar with InDesign you may be confusing yourself. Illustrator has no concept of “frames” as ID does. AI only understands paths and placed objects such as bitmaps. (Even AI’s “text frames” aren’t really “frames”: they’re just plain old paths with text flowed into them.)
[ETA: this next paragraph is incorrect; see reply below]
Thus if you select a group item containing a raster image with a clipping path above it, those will appear on the `selection` property as 2 separate items, not 1. It would be great if you could write `selection.groupItems[0]` and get the group that way, but AI’s ExtendScript is not that helpful. Since femkeblanco’s example code only resizes the first selected item (in this case the clipping path only), your “cropped image frame” in AI doesn’t resize as it would in ID.
What you really want is to find the GroupItem that contains both items and resize that. This is doable : every PageItem has a `container` property so you can recurse up through that to discover what group(s) contain each item. You can then figure out which of these containing groups (if any) is common to them all.
If you know the selection will always be a raster image with a grouped clipping path, it’s simple enough: just get their immediate container. OTOH, if you want a solution that will work reliably for any number of selected items, including items in deeply nested groups and/or in unrelated groups or not grouped at all, there’s a bit more algorithmic complexity involved.
An alternate approach is to use `PageItem.resize(…)`, making sure to use the `Transform.DOCUMENTORIGIN` option. That way, you can resize each item in turn while preserving their positioning relative to each other. This will work regardless of whether the items are grouped together or not. Once you’ve resized them all, you will have to calculate the distance to move each item to get them all to where you want them on the page. Not terribly complex to code, just a bit tedious and inelegant.
…
Couple other thoughts:
Another reason for wanting to use the `PageItem.resize(…)` method is that it can also scale stroke weights, fill patterns, and other attributes to preserve their proportions, whereas setting the width and height directly does not. Do whatever math you want to calculate the horizontal and vertical percentages (100.0 = 100%) for scaling the object to the size you want. Be aware that some attributes—e.g. round corners and other live effects—will not be scaled by either method unless you expand their appearances first.
TBH I couldn’t understand the logic being used to calculate the object’s height. If your intention is to scale both axes by the same amount, which I suspect is your goal if you’re fitting items to artboard, you need to rethink your math.
(If your intention is to scale the object’s horizontal and vertical axes by different amounts to deliberately distort it, you may want to outline its path strokes too before you resize so those strokes are likewise distorted.)
If you are still struggling for a solution, it will help if you post Before and After screenshots of what it is you are trying to achieve, plus a screenshot of your script’s incorrect result for comparison.
Copy link to clipboard
Copied
Thanks, for explaining things so nicely. Much appreciated.
The reason behind calculating object is based on brand guidelines. The frames or boxes needs to have a specific width and height. Width in most cases, remains the same which is equal to the width of the Artboard. However, the image(s) in these frames needs to be filled proportionally, and can be cropped to accordingly. So, we're not stretching/distorting the images, rather cropping it.
Thanks once again.
Copy link to clipboard
Copied
Can you expand on the issues of clipping masks (do you mean something like this?) and proportional resizing, preferably with screenshots?
Copy link to clipboard
Copied
Correcting myself: If you manually select a clipping path plus the placed/raster item it clips, it does appear in `selection` as a single GroupItem. (AI is smart enough to recognize you want them treated together. It’s when you select non-clipping groups that `selection` unhelpfully gives you all the individual paths instead.)
With that in mind, what you want is to set the clipping path’s width and height to your desired dimensions, then proportionally scale and reposition the image so that it completely fills that clipping path with any excess width/height cropped. The following code should handle that one particular use-case:
var doc = app.activeDocument;
var artboard = doc.artboards[0];
var rect = artboard.artboardRect;
var artboardWidth = rect[2] - rect[0];
var sel = doc.selection;
function calculateClippingPathHeight(width) {
return width * 0.8; // use whatever calculation you want here
}
function recenterItemInBounds(item, bounds) {
var p = item.position;
p[0] = bounds[0] - (item.width - (bounds[2] - bounds[0])) / 2;
p[1] = bounds[1] + (item.height - (bounds[1] - bounds[3])) / 2;
item.position = p;
}
// assume a clipping path with a single placed/raster item behind it
if (sel.length === 1 && sel[0].typename === 'GroupItem' &&
sel[0].pageItems.length === 2 && sel[0].pageItems[0].clipping) {
var group = sel[0];
var clip = group.pageItems[0];
var image = group.pageItems[1];
// set the desired width and height of the clipping path
clip.width = artboardWidth;
clip.height = calculateClippingPathHeight(clip.width);
// calculate proportional scale factor for image so that it fills the clipping path
var scale = Math.max(clip.width / image.width, clip.height / image.height) * 100;
image.resize(scale, scale);
// recenter the image in the clipping path
recenterItemInBounds(image, clip.geometricBounds);
// recenter the group on the artboard
recenterItemInBounds(group, artboard.artboardRect);
} else {
alert("Selection is not a clipped image.");
}
Developing a more general-purpose script which can process any number and combination of selected items, position items according to different rules, etc is left as an exercise to the reader.