Skip to content

Instantly share code, notes, and snippets.

@creold
Last active June 7, 2024 15:09
Show Gist options
  • Save creold/d7d8342bc6765f30a0a246d7f88b387a to your computer and use it in GitHub Desktop.
Save creold/d7d8342bc6765f30a0a246d7f88b387a to your computer and use it in GitHub Desktop.
Added option to remove all previous artboards, support clipping groups size
/*
Author: Alexander Ladygin (i@ladygin.pro)
Program version: Adobe Illustrator CC+
Name: createArtboardsFromTheSelection.jsx;
Copyright (c) 2018
www.ladyginpro.ru
Modification by Sergey Osokin (https://github.com/creold)
Added option to remove all previous artboards
Added support clipping groups size
*/
$.errorMessage = function (err) {alert(err + '\n' + err.line);};
$.getUnits = function (val, def) {return 'px,pt,mm,cm,in,pc'.indexOf(val.slice(-2)) > -1 ? val.slice(-2) : def;};
$.convertUnits = function (obj, b) {if (obj === undefined) {return obj;}if (b === undefined) {b = 'px';}if (typeof obj === 'number') {obj = obj + 'px';}if (typeof obj === 'string') {var unit = $.getUnits(obj),val = parseFloat(obj);if (unit && !isNaN(val)) {obj = val;}else if (!isNaN(val)) {obj = val; unit = 'px';}}if (((unit === 'px') || (unit === 'pt')) && (b === 'mm')) {obj = parseFloat(obj) / 2.83464566929134;}else if (((unit === 'px') || (unit === 'pt')) && (b === 'cm')) {obj = parseFloat(obj) / (2.83464566929134 * 10);}else if (((unit === 'px') || (unit === 'pt')) && (b === 'in')) {obj = parseFloat(obj) / 72;}else if ((unit === 'mm') && ((b === 'px') || (b === 'pt'))) {obj = parseFloat(obj) * 2.83464566929134;}else if ((unit === 'mm') && (b === 'cm')) {obj = parseFloat(obj) * 10;}else if ((unit === 'mm') && (b === 'in')) {obj = parseFloat(obj) / 25.4;}else if ((unit === 'cm') && ((b === 'px') || (b === 'pt'))) {obj = parseFloat(obj) * 2.83464566929134 * 10;}else if ((unit === 'cm') && (b === 'mm')) {obj = parseFloat(obj) / 10;}else if ((unit === 'cm') && (b === 'in')) {obj = parseFloat(obj) * 2.54;}else if ((unit === 'in') && ((b === 'px') || (b === 'pt'))) {obj = parseFloat(obj) * 72;}else if ((unit === 'in') && (b === 'mm')) {obj = parseFloat(obj) * 25.4;}else if ((unit === 'in') && (b === 'cm')) {obj = parseFloat(obj) * 25.4;}return parseFloat(obj);};
function inputNumberEvents(ev, _input, min, max, callback){
var step,
_dir = (ev.keyName ? ev.keyName.toLowerCase().slice(0,1) : '#none#'),
_value = parseFloat(_input.text),
units = (',px,pt,mm,cm,in,'.indexOf(_input.text.length > 2 ? (',' + _input.text.replace(/ /g, '').slice(-2) + ',') : ',!,') > -1 ? _input.text.replace(/ /g, '').slice(-2) : '');
min = (min === undefined ? 0 : min);
max = (max === undefined ? Infinity : max);
step = (ev.shiftKey ? 10 : (ev.ctrlKey ? .1 : 1));
if (isNaN(_value)) {
_input.text = min;
} else {
_value = (((_dir === 'u')) ? _value + step : (((_dir === 'd')) ? _value - step : false));
if (_value !== false) {
_value = (_value <= min ? min : (_value >= max ? max : _value))
_input.text = _value;
if (callback instanceof Function) callback(ev, _value, _input, min, max, units);
else if (units) _input.text = parseFloat(_input.text) + ' ' + units;
} else if (units) _input.text = parseFloat(_input.text) + ' ' + units;
}
}
function doubleValues(ev, __value, items) {
if (ev.altKey && ((ev.keyName === 'Left') || (ev.keyName === 'Right'))) {
var i = items.length;
if (i > 0) while (i--) items[i].text = __value;
}
}
var scriptName = 'CAFTS',
copyright = ' \u00A9 www.ladyginpro.ru',
settingFile = {
name: scriptName + '__setting.json',
folder: Folder.myDocuments + '/LA_AI_Scripts/'
};
var win = new Window('dialog', 'Create Artboard From the Selection');
win.orientation = 'column';
win.alignChildren = ['fill', 'fill'];
var panel = win.add('panel', undefined, 'Selection bounds:');
panel.orientation = 'column';
panel.alignChildren = ['fill', 'fill'];
panel.margins = [10, 15, 10, 10];
var eachSel = panel.add('radiobutton', undefined, 'Each in the Selection'),
selBnds = panel.add('radiobutton', undefined, 'Only Selection Bounds'),
isRename = panel.add('checkbox', undefined, 'Set Name From Element');
isRename.value = true;
eachSel.value = true;
eachSel.onClick = function() { isRename.enabled = true; }
selBnds.onClick = function() { isRename.enabled = false; }
with (panel.add('group')) {
orientation = 'column';
alignChildren = 'fill';
with(add('group')) {
orientation = 'row';
with(add('group')) {
orientation = 'column';
alignChildren = 'left';
add('statictext', undefined, 'Bleed Top:');
var bleedTop = add('edittext', [0, 0, 80, 25], '0 px');
bleedTop.addEventListener('keydown', function (e) {
inputNumberEvents(e, this, 0, Infinity);
doubleValues(e, this.text, (e.shiftKey ? [bleedTop, bleedRight, bleedBottom, bleedLeft] : [bleedTop, bleedBottom]));
});
}
with(add('group')) {
orientation = 'column';
alignChildren = 'left';
add('statictext', undefined, 'Bleed Right:');
var bleedRight = add('edittext', [0, 0, 80, 25], '0 px');
bleedRight.addEventListener('keydown', function (e) {
inputNumberEvents(e, this, 0, Infinity);
doubleValues(e, this.text, (e.shiftKey ? [bleedTop, bleedRight, bleedBottom, bleedLeft] : [bleedRight, bleedLeft]));
});
}
}
with(add('group')) {
orientation = 'row';
with(add('group')) {
orientation = 'column';
alignChildren = 'left';
add('statictext', undefined, 'Bleed Bottom:');
var bleedBottom = add('edittext', [0, 0, 80, 25], '0 px');
bleedBottom.addEventListener('keydown', function (e) {
inputNumberEvents(e, this, 0, Infinity);
doubleValues(e, this.text, (e.shiftKey ? [bleedTop, bleedRight, bleedBottom, bleedLeft] : [bleedTop, bleedBottom]));
});
}
with(add('group')) {
orientation = 'column';
alignChildren = 'left';
add('statictext', undefined, 'Bleed Left:');
var bleedLeft = add('edittext', [0, 0, 80, 25], '0 px');
bleedLeft.addEventListener('keydown', function (e) {
inputNumberEvents(e, this, 0, Infinity);
doubleValues(e, this.text, (e.shiftKey ? [bleedTop, bleedRight, bleedBottom, bleedLeft] : [bleedRight, bleedLeft]));
});
}
}
}
var bndsPanel = win.add('panel', undefined, 'Item Bounds:');
bndsPanel.orientation = 'row';
bndsPanel.alignChildren = ['fill', 'fill'];
bndsPanel.margins = [10, 15, 10, 7];
var bndsVis = bndsPanel.add('radiobutton', undefined, 'Visible');
var bndsGeo = bndsPanel.add('radiobutton', undefined, 'Geometric');
bndsVis.value = true;
var abPanel = win.add('panel', undefined, 'Previous Artboards:');
abPanel.orientation = 'row';
abPanel.alignChildren = ['fill', 'fill'];
abPanel.margins = [10, 15, 10, 7];
var isKeepAb = abPanel.add('radiobutton', undefined, 'Keep');
isKeepAb.value = true;
var isRemoveAb = abPanel.add('radiobutton', undefined, 'Remove');
var winButtons = win.add('group');
winButtons.alignChildren = ['fill', 'fill'];
winButtons.margins = [0, 0, 0, 0];
var cancel = winButtons.add('button', undefined, 'Cancel', { name: 'cancel' });
cancel.helpTip = 'Press Esc to Close';
cancel.onClick = function () { win.close(); }
var ok = winButtons.add('button', [0, 0, 100, 30], 'OK', { name: 'ok' });
ok.helpTip = 'Press Enter to Run';
ok.onClick = startAction;
ok.active = true;
var copyright = win.add('statictext', undefined, '\u00A9 www.ladyginpro.ru');
copyright.justify = 'center';
function startAction() {
var items = selection,
i = items.length,
$bounds = [],
bleed = [
$.convertUnits(bleedLeft.text, 'px'),
$.convertUnits(bleedTop.text, 'px'),
$.convertUnits(bleedRight.text, 'px'),
$.convertUnits(bleedBottom.text, 'px')
],
type = (bndsVis.value ? 'visible' : 'geometric') + 'Bounds';
// Artboards from each selected object
if (eachSel.value) {
while (i--) {
var bounds = getVisibleBounds(items[i], type);
$bounds = [
bounds[0] - bleed[0],
bounds[1] + bleed[1],
bounds[2] + bleed[2],
bounds[3] - bleed[3]
];
if (eachSel.value && isRename.value && items[i].name) {
activeDocument.artboards.add($bounds).name = items[i].name;
} else {
activeDocument.artboards.add($bounds);
}
}
} else { // Artboard from total selection bounds
var totalBounds = null;
while (i--) {
var currBounds = getVisibleBounds(items[i], type);
if (totalBounds == null) {
totalBounds = currBounds;
} else {
totalBounds[0] = Math.min(totalBounds[0], currBounds[0]);
totalBounds[1] = Math.max(totalBounds[1], currBounds[1]);
totalBounds[2] = Math.max(totalBounds[2], currBounds[2]);
totalBounds[3] = Math.min(totalBounds[3], currBounds[3]);
}
};
try {
activeDocument.artboards.add([
totalBounds[0] - bleed[0],
totalBounds[1] + bleed[1],
totalBounds[2] + bleed[2],
totalBounds[3] - bleed[3]
]);
} catch (e) {}
}
if (isRemoveAb.value) {
var prevArtboards = activeDocument.artboards.length - (eachSel.value ? items.length : 1);
for (var j = prevArtboards - 1; j >= 0; j--) {
activeDocument.artboards.remove(j);
}
}
win.close();
}
function saveSettings() {
var $file = new File(settingFile.folder + settingFile.name),
data = [
eachSel.value,
selBnds.value,
isRename.value,
bndsVis.value,
bndsGeo.value,
isKeepAb.value,
bleedTop.text,
bleedRight.text,
bleedBottom.text,
bleedLeft.text
].toString();
$file.open('w');
$file.write(data);
$file.close();
}
function loadSettings() {
var $file = File(settingFile.folder + settingFile.name);
if ($file.exists) {
try {
$file.open('r');
var data = $file.read().split('\n'),
$main = data[0].split(',');
eachSel.value = ($main[0] === 'true');
selBnds.value = ($main[1] === 'true');
isRename.value = ($main[2] === 'true');
bndsVis.value = ($main[3] === 'true');
bndsGeo.value = ($main[4] === 'true');
isKeepAb.value = ($main[5] === 'true');
isRemoveAb.value = ($main[5] === 'false');
bleedTop.text = $main[6];
bleedRight.text = $main[7];
bleedBottom.text = $main[8];
bleedLeft.text = $main[9];
isRename.enabled = eachSel.value;
} catch (e) {}
$file.close();
}
}
win.onClose = function () {
saveSettings();
return true;
}
function checkSettingFolder() {
var $folder = new Folder(settingFile.folder);
if (!$folder.exists) $folder.create();
}
// Get the actual "visible" bounds
// https://github.com/joshbduncan/illustrator-scripts/blob/main/jsx/DrawVisibleBounds.jsx
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 = selection[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;
}
checkSettingFolder();
loadSettings();
win.center();
win.show();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment