Last active
January 8, 2025 15:13
-
-
Save creold/283ce0dc3b5349cba0f7b3a4946ffbe1 to your computer and use it in GitHub Desktop.
Select objects inside active artboard. Adobe Illustrator script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Select objects inside active artboard | |
Author: Sergey Osokin, email: [email protected] | |
Check my other scripts: https://github.com/creold | |
Donate (optional): | |
If you find this script helpful, you can buy me a coffee | |
- via Buymeacoffee: https://www.buymeacoffee.com/aiscripts | |
- via Donatty https://donatty.com/sergosokin | |
- via DonatePay https://new.donatepay.ru/en/@osokin | |
- via YooMoney https://yoomoney.ru/to/410011149615582 | |
*/ | |
//@target illustrator | |
app.preferences.setBooleanPreference('ShowExternalJSXWarning', false); // Fix drag and drop a .jsx file | |
function main() { | |
if (!/illustrator/i.test(app.name)) { | |
alert('Wrong application\nRun script from Adobe Illustrator', 'Script error'); | |
return; | |
} | |
if (parseFloat(app.version) < 16) { | |
alert('Wrong app version\nSorry, script only works in Illustrator CS6 and later', 'Script error'); | |
return false; | |
} | |
if (!documents.length) { | |
alert('No documents\nOpen a document and try again', 'Script error'); | |
return; | |
} | |
var tolerance = 1; // Object positions tolerance | |
var doc = app.activeDocument; | |
var docUnits = getUnits(); | |
var sf = doc.scaleFactor ? doc.scaleFactor : 1; // Scale factor for Large Canvas mode | |
var idx = doc.artboards.getActiveArtboardIndex(); | |
var abBnds = doc.artboards[idx].artboardRect; | |
var currTolerance = convertUnits( tolerance, docUnits, 'px' ) / sf; | |
app.executeMenuCommand('selectall'); | |
app.redraw(); | |
var items = getItems(app.selection); | |
app.selection = null; | |
for (var i = items.length - 1; i >= 0; i--) { | |
var itemBnds = getVisibleBounds(items[i], 'geometricBounds'); | |
if (!isOverlap(itemBnds, abBnds, currTolerance)) { | |
items[i].selected = true; | |
} | |
} | |
var currSel = app.selection; | |
app.executeMenuCommand('selectallinartboard'); | |
app.redraw(); | |
app.executeMenuCommand('Inverse menu item'); | |
currSel.push.apply(currSel, app.selection); | |
app.selection = currSel; | |
app.redraw(); | |
app.executeMenuCommand('Inverse menu item'); | |
} | |
/** | |
* Get active document ruler units | |
* @returns {string} - Shortened units | |
*/ | |
function getUnits() { | |
if (!documents.length) return ''; | |
var key = activeDocument.rulerUnits.toString().replace('RulerUnits.', ''); | |
switch (key) { | |
case 'Pixels': return 'px'; | |
case 'Points': return 'pt'; | |
case 'Picas': return 'pc'; | |
case 'Inches': return 'in'; | |
case 'Millimeters': return 'mm'; | |
case 'Centimeters': return 'cm'; | |
// Added in CC 2023 v27.1.1 | |
case 'Meters': return 'm'; | |
case 'Feet': return 'ft'; | |
case 'FeetInches': return 'ft'; | |
case 'Yards': return 'yd'; | |
// Parse new units in CC 2020-2023 if a document is saved | |
case 'Unknown': | |
var xmp = activeDocument.XMPString; | |
if (/stDim:unit/i.test(xmp)) { | |
var units = /<stDim:unit>(.*?)<\/stDim:unit>/g.exec(xmp)[1]; | |
if (units == 'Meters') return 'm'; | |
if (units == 'Feet') return 'ft'; | |
if (units == 'FeetInches') return 'ft'; | |
if (units == 'Yards') return 'yd'; | |
return 'px'; | |
} | |
break; | |
default: return 'px'; | |
} | |
} | |
/** | |
* Convert a value from one set of units to another | |
* @param {string} value - The numeric value to be converted | |
* @param {string} currUnits - The current units of the value (e.g., 'in', 'mm', 'pt') | |
* @param {string} newUnits - The desired units for the converted value (e.g., 'in', 'mm', 'pt') | |
* @returns {number} - The converted value in the specified units | |
*/ | |
function convertUnits(value, currUnits, newUnits) { | |
return UnitValue(value, currUnits).as(newUnits); | |
} | |
/** | |
* Get items from an Adobe Illustrator collection, including nested pageItems. | |
* @param {Object} coll - The Adobe Illustrator collection to retrieve items from | |
* @returns {Array} result - Return a JavaScript Array containing relevant items from the given collection | |
*/ | |
function getItems(coll) { | |
var results = []; | |
for (var i = 0; i < coll.length; i++) { | |
var item = coll[i]; | |
if (item.pageItems && item.pageItems.length) { | |
results = [].concat(results, getItems(item.pageItems)); | |
} else { | |
results.push(item); | |
} | |
} | |
return results; | |
} | |
/** | |
* Get the actual "visible" bounds | |
* https://github.com/joshbduncan/illustrator-scripts/blob/main/jsx/DrawVisibleBounds.jsx | |
* @param {Object} obj - The target object | |
* @param {string} type - The object bounds type | |
* @returns {Array} - An array representing the actual bounds | |
*/ | |
function getVisibleBounds(obj, type) { | |
if (arguments.length == 1 || type == undefined) type = 'geometricBounds'; | |
var doc = app.activeDocument; | |
var bnds, clippedItem, tmpItem, tmpLayer; | |
var curItem; | |
if (obj.typename === 'GroupItem') { | |
if (obj.clipped) { | |
// Check all sub objects to find the clipping path | |
for (var i = 0; i < obj.pageItems.length; i++) { | |
curItem = obj.pageItems[i]; | |
if (curItem.clipping) { | |
clippedItem = curItem; | |
break; | |
} else if (curItem.typename === 'CompoundPathItem') { | |
if (!curItem.pathItems.length) { | |
// Catch compound path items with no pathItems | |
// via William Dowling @ github.com/wdjsdev | |
tmpLayer = doc.layers.add(); | |
tmpItem = curItem.duplicate(tmpLayer); | |
app.executeMenuCommand('deselectall'); | |
tmpItem.selected = true; | |
app.executeMenuCommand('noCompoundPath'); | |
tmpLayer.hasSelectedArtwork = true; | |
app.executeMenuCommand('group'); | |
clippedItem = item[0]; | |
break; | |
} else if (curItem.pathItems[0].clipping) { | |
clippedItem = curItem; | |
break; | |
} | |
} | |
} | |
if (!clippedItem) clippedItem = obj.pageItems[0]; | |
bnds = clippedItem[type]; | |
if (tmpLayer) { | |
tmpLayer.remove(); | |
tmpLayer = undefined; | |
} | |
} else { | |
// If the object is not clipped | |
var subObjBnds; | |
var allBoundPoints = [[], [], [], []]; | |
// Get the bounds of every object in the group | |
for (var i = 0; i < obj.pageItems.length; i++) { | |
curItem = obj.pageItems[i]; | |
subObjBnds = getVisibleBounds(curItem, type); | |
allBoundPoints[0].push(subObjBnds[0]); | |
allBoundPoints[1].push(subObjBnds[1]); | |
allBoundPoints[2].push(subObjBnds[2]); | |
allBoundPoints[3].push(subObjBnds[3]); | |
} | |
// Determine the groups bounds from it sub object bound points | |
bnds = [ | |
Math.min.apply(Math, allBoundPoints[0]), | |
Math.max.apply(Math, allBoundPoints[1]), | |
Math.max.apply(Math, allBoundPoints[2]), | |
Math.min.apply(Math, allBoundPoints[3]), | |
]; | |
} | |
} else { | |
bnds = obj[type]; | |
} | |
return bnds; | |
} | |
/** | |
* Determine whether two bounding boxes overlap, within a specified tolerance | |
* @param {Array} bnds1 - The first bounding box represented as an array of four numbers [left, top, right, bottom] | |
* @param {Array} bnds2 - The second bounding box represented as an array of four numbers [left, top, right, bottom] | |
* @param {number} t - The tolerance value to use when checking for overlap | |
* @returns {boolean} - True if the bounding boxes overlap, false otherwise | |
*/ | |
function isOverlap(bnds1, bnds2, t) { | |
if ((bnds1[2] <= bnds2[0] + t || bnds1[0] >= bnds2[2] - t) || | |
(bnds1[3] >= bnds2[1] - t || bnds1[1] <= bnds2[3] + t)) { | |
return false; | |
} else { | |
return true; | |
} | |
} | |
// Run script | |
try { | |
main(); | |
} catch (err) {} |
Author
creold
commented
Dec 19, 2024
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment