/* Select objects inside active artboard Author: Sergey Osokin, email: hi@sergosokin.ru 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) {}