Copy link to clipboard
Copied
I have a MacOS Illustrator ExtendScript that steps out images on a layout with a designated gap between each. It currently uses the image canvas size for the spacing. I'd like to use the pixel bounds instead (ignoring white or transparent backgrounds).
Is it possible to get this information from the images with Illustrator ExtendScript, without using something that would need to be installed (i.e., ImageMagic, etc.)?
I thought perhaps using Image Trace » Silhouette » Expand might work, then get those dimensions, but am having difficulty removing the bounding box that's created with .expandTracing():
var selectedItem = app.activeDocument.selection[0];
// Duplicate the selected item to preserve the original
var duplicateItem = selectedItem.duplicate();
// Rasterize the duplicate item
var rasterItem = app.activeDocument.rasterize(duplicateItem);
// Perform Image Trace
var tracedItem = rasterItem.trace();
// Set silhouette tracing options
var tracingOptions = tracedItem.tracing.tracingOptions;
tracingOptions.tracingMode = TracingModeType.TRACINGMODEBLACKANDWHITE;
tracingOptions.ignoreWhite = true;
tracingOptions.threshold = 254;
// Expand
tracedItem.tracing.expandTracing();
Thoughts?
Hi @Chris.S, see if this helps. I've made your code into a function that returns a bounds, and tweaked the rasterization and image trace options to (hopefully!) improve the accuracy. It won't be super accurate though, and tends to be larger than the source art, so I've included a `chokeAmount` that moves it in a little (just leave empty or zero if not needed). The `drawRectangle` function is just for the demo and testing—you don't need it in your final script. Good luck!
- Mark
(function () {
...
Copy link to clipboard
Copied
Hi @Chris.S, see if this helps. I've made your code into a function that returns a bounds, and tweaked the rasterization and image trace options to (hopefully!) improve the accuracy. It won't be super accurate though, and tends to be larger than the source art, so I've included a `chokeAmount` that moves it in a little (just leave empty or zero if not needed). The `drawRectangle` function is just for the demo and testing—you don't need it in your final script. Good luck!
- Mark
(function () {
var doc = app.activeDocument;
var selectedItem = doc.selection[0];
var myBounds = getRasterizedBounds(doc, selectedItem, 0.25);
// just for showing bounds, draw a rectangle around it
var rectangle = drawRectangleIllustrator(selectedItem.parent, myBounds, {
filled: false,
stroked: true,
strokeWidth: 0.3,
strokeColor: doc.swatches[4].color, // just a guess!
});
})();
/**
* Returns bounds of non-transparent region of `item`.
* @param {Dcument} doc
* @param {RasterItem|PlacedItem} item - the target item.
* @param {Number} chokeAmount - amount, in points, to contract the bounds by.
* @returns {Array<Number>}
*/
function getRasterizedBounds(doc, item, chokeAmount) {
chokeAmount = chokeAmount || 0;
// Duplicate the selected item to preserve the original
var duplicateItem = item.duplicate();
// set up the raserization to maximize fidelity
var rasterizeOptions = new RasterizeOptions();
rasterizeOptions.antiAliasingMethod = AntiAliasingMethod.ARTOPTIMIZED;
rasterizeOptions.clippingMask = false;
rasterizeOptions.padding = 0;
rasterizeOptions.convertSpotColors = true;
rasterizeOptions.resolution = 1200; // set this according to your needs
rasterizeOptions.convertTextToOutlines = true;
rasterizeOptions.transparency = true;
// Rasterize the duplicate item
var rasterItem = doc.rasterize(duplicateItem, undefined, rasterizeOptions);
// Perform Image Trace
var tracedItem = rasterItem.trace();
// Set silhouette tracing options
var tracingOptions = tracedItem.tracing.tracingOptions;
tracingOptions.tracingMode = TracingModeType.TRACINGMODEBLACKANDWHITE;
tracingOptions.ignoreWhite = true;
tracingOptions.threshold = 254;
tracingOptions.noiseFidelity = 0;
tracingOptions.cornerFidelity = 100;
tracingOptions.pathFidelity = 50;
tracingOptions.padding = 0;
// Expand
var group = tracedItem.tracing.expandTracing();
// Remove outer frame
group.pageItems[group.pageItems.length - 1].remove();
// This is what we want
var bounds = group.geometricBounds;
// Clean up
group.remove();
return [
bounds[0] + chokeAmount,
bounds[1] - chokeAmount,
bounds[2] - chokeAmount,
bounds[3] + chokeAmount,
];
};
/**
* Draws a rectangle to the document.
* @param {Document|Layer|GroupItem} container - an Illustrator container.
* @param {Array<Number>} bounds - [T, L, B, R]
* @param {Object} props - properties to assign to the rectangle.
* @return {PathItem}
*/
function drawRectangleIllustrator(container, bounds, properties) {
properties = properties || {};
var rectangle = container.pathItems.rectangle(bounds[1], bounds[0], bounds[2] - bounds[0], -(bounds[3] - bounds[1])); // TLWH
// defaults
rectangle.filled = true;
rectangle.stroked = false;
// apply properties
for (var key in properties)
if (properties.hasOwnProperty(key))
rectangle[key] = properties[key];
return rectangle;
};
Copy link to clipboard
Copied
Thank you @m1b ! The line below is what I was looking for
group.pageItems[group.pageItems.length - 1].remove();
Coincidentally, it appears going directly to .trace() and skipping the .rasterize() beforehand produces a result that is a bit accurate (raster produces a larger frame and larger offset), as shown in the attached screenshot. Not sure why both methods shift it down and to the right a bit, but with the trace alone method it's less than 0.25pt, so I can live with that... or shift the results with an offset.
Assuming this is probably the best/fastest method to figure out where the image bounds are, excluding white and transparent backgrounds with Illustrator ExtendScript, or any other ideas?