Copy link to clipboard
Copied
Hi!
I'm looking for a script that will allow you to select some objects or symbols in your AI-file and then select some of your symbols from the symbols-library in your file and then randomly replace the original objects/symbols with the symbols selected. I have found a few scripts that does basically this but with random replacement of selected colours, transparency or angles but I need one for randomly replacing symbols.
Can someone help?
Try this. it will use all symbols in document.
var doc = app.activeDocument;
var sym = doc.symbols;
var sel = doc.selection;
for(var i = 0; i < sel.length; i++){
var place = doc.symbolItems.add(sym[Math.floor(Math.random() * sym.length)]);
place.height = sel.height;
place.width = sel.width;
place.top = sel.top;
place.left = sel.left;
sel.remove();
place.selected = true;
}
I revised an alternate workaround to selecting the symbols you want to randomize by placing them in a specific layer. On first run it will create the layer if it can't find it. Also revised the original script to size proportinatly based on height, and place the items within the original parent layer:
var doc = app.activeDocument;
var sym = doc.symbols;
var fullSelection = doc.selection;
try { doc.layers["Symbols_To_Place"] }
catch (e) {
symLyr = doc.layers.add();
symLyr.name = "Symbols_T
...
Copy link to clipboard
Copied
Try this. it will use all symbols in document.
var doc = app.activeDocument;
var sym = doc.symbols;
var sel = doc.selection;
for(var i = 0; i < sel.length; i++){
var place = doc.symbolItems.add(sym[Math.floor(Math.random() * sym.length)]);
place.height = sel.height;
place.width = sel.width;
place.top = sel.top;
place.left = sel.left;
sel.remove();
place.selected = true;
}
Copy link to clipboard
Copied
That works perfectly!!!
Thanks so much!!!
Copy link to clipboard
Copied
Hi!
I need the exact action to do with a script. But it is my first time using script, how can I install it?
I tried through extendscript toolkit, but the script doesnt appear in illustrator.
Copy link to clipboard
Copied
try this
Installing scripts in the Scripts menu
To include a script in the Scripts menu (File > Scripts), save the script in the Scripts folder, located in the
/lllustrator CC/Presets folder in your lllustrator CC installation directory, for example C:\Program Files\Adobe\Adobe Illustrator CC 2018\Presets\en_US\Scripts
.
The script’s filename, minus
the file extension, appears in the Scripts menu.
Scripts that you add to the Scripts folder while Illustrator is running do not appear in the Scripts menu until
the next time you launch Illustrator.
Any number of scripts can be installed in the Scripts menu. If you have many scripts, use subfolders in the
Scripts folder to help organize the scripts in the Scripts menu. Each subfolder is displayed as a separate
submenu containing the scripts in that subfolder.
Executing scripts from the Other Scripts menu item
The Other Scripts item at the end of the Scripts menu (File > Scripts > Other Scripts) allows you to execute
scripts that are not installed in the Scripts folder.
Selecting Other Scripts displays a Browse dialog, which you use to navigate to a script file. When you select
the file, the script is executed.
Copy link to clipboard
Copied
I had to modify this for it to work in 2023:
var doc = app.activeDocument;
var sym = doc.symbols;
var fullSelection = doc.selection;
for (var i = 0; i < fullSelection.length; i++) {
var sel = fullSelection[i];
var place = doc.symbolItems.add(sym[Math.floor(Math.random() * sym.length)]);
place.height = sel.height;
place.width = sel.width;
place.top = sel.top;
place.left = sel.left;
sel.remove();
place.selected = true;
}
Simply had to set the whole selection as a variable first and make sure sel was set to an instance/iteration.
Copy link to clipboard
Copied
I revised an alternate workaround to selecting the symbols you want to randomize by placing them in a specific layer. On first run it will create the layer if it can't find it. Also revised the original script to size proportinatly based on height, and place the items within the original parent layer:
var doc = app.activeDocument;
var sym = doc.symbols;
var fullSelection = doc.selection;
try { doc.layers["Symbols_To_Place"] }
catch (e) {
symLyr = doc.layers.add();
symLyr.name = "Symbols_To_Place";
alert("Select Symbols to randomize\nBy placing in \"Symbols_To_Place\" Layer.")
}
var symTgt = doc.layers["Symbols_To_Place"].symbolItems;
var symAry = [];
for (var s = 0; s < symTgt.length; s++) {
nm = symTgt[s].symbol.name;
symAry.push(nm);
}
for (var i = 0; i < fullSelection.length; i++) {
var sel = fullSelection[i];
var place = doc.symbolItems.add(sym[symAry[Math.floor(Math.random() * symAry.length)]]);
place.move(sel, ElementPlacement.PLACEBEFORE);
//Base it off the height
percent = sel.height / place.height;
place.height = sel.height;
place.width = place.width * percent;
place.top = sel.top;
place.left = sel.left;
sel.remove();
place.selected = true;
}
Copy link to clipboard
Copied
Great script! Could it be modified to use only selected symbols from the Symbols palette?
Copy link to clipboard
Copied
The problem is that with scripting they don't let us know what symbols are even selected in the Symbols palette. However through ponderous workarounds, we can sort of get there.
If the action of using the Symbol panel's flyout menu's delete or duplicate commands is recordable, we can play it with a script. This means that we can read all the symbols in the document's symbols collection and then perform one of those actions and compare the before/after difference of what was there and not. However, if you do the delete action, you will have to do an Undo to get the symbols back and worse it may mangle some symbol instances you did not wish to disturb if those symbols are removed.
With Duplicate action all you have to do is remove all the symbols which are added that are considered new.
I can try this sometime this weekend and see if it works!
Copy link to clipboard
Copied
Silly-V,
Thanks for your response.
Very kind of you to test a workaround.
Take care.
Copy link to clipboard
Copied
It worked. However, one must be wary of Illustrator's symbol naming copy conventions as new symbols get a sequential number on the end of them. When you copy "Symbol 1", it becomes called "Symbol 2". But when you copy both "Symbol 1" and "Symbol 2" you get "Symbol 3" and "Symbol 4". We could have extra code that does a more thorough check that tries to match that "Symbol 3" is a copy of "Symbol 1" and so on, but if you rename "Symbol 1" in set ["Symbol 1", "Symbol 2"] to "Symbol 23", the next duplicated symbol name would be "Symbol 3". And if you have ["Symbol 1", "Symbol 2", "Symbol 4"], the duplicated copies will fill a spot for "Symbol 3" but skip over and become "Symbol 5" the next duplication.
With all this happening, it's better to just stick with a convention of don't name symbols with digits on the end or don't copy symbols without renaming them to something less-generic. In my code it will only get the latest copy name so looking to match an auto-named "Symbol 3" will actually find "Symbol 4" in ["Symbol 1", "Symbol 2", "Symbol 4"] but auto-named "Symbol 5" will find "Symbol 4" in ["Symbol 1", "Symbol 2", "Symbol 3", "Symbol 4"].
#target illustrator
function test () {
if (typeof(String.escapeForRegexp) != "function") {
String.prototype.escapeForRegexp = function () {
return this.replace(/([\/.*+?|()[\]{}\\^$])/g, "\\$1");
};
}
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function(searchElement, fromIndex) {
var k;
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
var o = Object(this);
var len = o.length >>> 0;
if (len === 0) {
return -1;
}
var n = +fromIndex || 0;
if (Math.abs(n) === Infinity) {
n = 0;
}
if (n >= len) {
return -1;
}
k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
while (k < len) {
if (k in o && o[k] === searchElement) {
return k;
}
k++;
}
return -1;
};
};
/**
* Matches a name of a new copied symbol "Symbol 1" to a name in the list of symbols ["Symbol", "Other Symbol"] before processing.
* Will have no choice but to use latest copy name: "Symbol 3" in ["Symbol", "Symbol 1", "Symbol 2"] will result in "Symbol 2" even if the copied original was actually "Symbol 1".
* {string[]} originalSymbolNames - Array of original symbol names before any were duplicated via action.
* {string} symbolNameToCheck - The name of a new copied symbol.
* {string} - Name of the original symbol to use, or name of the last copy of that symbol in the symbols panel.
*/
function getLatestSymbolCopyName (originalSymbolNames, symbolNameToCheck) {
var thisSymbolName;
var previousCopyNames = [];
var endSuffixRx = /\s\d+$/;
for (var i = 0; i < originalSymbolNames.length; i++) {
thisSymbolName = originalSymbolNames[i];
if (thisSymbolName.replace(endSuffixRx, "") == symbolNameToCheck.replace(endSuffixRx, "")) {
previousCopyNames.push(thisSymbolName);
}
}
previousCopyNames.sort(function (a, b) {
if (endSuffixRx.test(a) && !endSuffixRx.test(b)) {
return true;
} else if (!endSuffixRx.test(a) && endSuffixRx.test(b)) {
return false;
}
var aSuffix = a.match(endSuffixRx)[0].substr(1) * 1;
var bSuffix = b.match(endSuffixRx)[0].substr(1) * 1;
return aSuffix < bSuffix;
});
var latestCopyName = previousCopyNames[0];
return latestCopyName;
};
/**
* Replaces a symbol instance art object's symbol reference to another symbol definition.
* {AiSymbolItem} symbolArt - The symbol instance inside the document (on an artboard/in a layer).
* {AiSymbol} symbolDefinition - Symbol definition in the Symbols panel.
*/
function replaceSymbolReference (symbolArt, symbolDefinition) {
symbolArt.symbol = symbolDefinition;
};
function replaceDocumentArt (doc, docArt, symbolDefinition) {
var newPlacedArt = doc.symbolItems.add(symbolDefinition);
newPlacedArt.move(docArt, ElementPlacement.PLACEAFTER);
newPlacedArt.height = docArt.height;
newPlacedArt.width = docArt.width;
newPlacedArt.top = docArt.top;
newPlacedArt.left = docArt.left;
docArt.remove();
return newPlacedArt;
};
var doc = app.activeDocument;
doc.layers[0].visible = true;
doc.layers[0].locked = false;
var sel = doc.selection;
if (sel.length == 0) {
alert("No selection");
return;
}
var sym = doc.symbols;
var originalSymbolNames = [];
var endSuffixRx = /\s\d+$/;
var thisSymbol, thisSymbolName;
for (var i = 0; i < sym.length; i++) {
thisSymbol = sym[i];
thisSymbolName = thisSymbol.name;
originalSymbolNames.push(thisSymbolName);
}
app.doScript("Duplicate Symbol", "Duplicate Symbol Set");
var newSymbolNames = [];
for (var i = 0; i < sym.length; i++) {
thisSymbol = sym[i];
thisSymbolName = thisSymbol.name;
if (originalSymbolNames.indexOf(thisSymbolName) == -1) {
newSymbolNames.push(thisSymbolName);
}
}
if (newSymbolNames.length == 0) {
alert("No symbols were found to be selected.");
return;
}
// clean up copied symbols.
for (var i = 0; i < newSymbolNames.length; i++) {
thisSymbolName = newSymbolNames[i];
thisSymbol = doc.symbols.getByName(thisSymbolName);
thisSymbol.remove();
}
var selectedSymbolNames = [];
var thisOriginalName;
var thisNewName;
var latestCopyName;
for (var i = 0; i < originalSymbolNames.length; i++) {
thisOriginalName = originalSymbolNames[i];
for (var j = 0; j < newSymbolNames.length; j++) {
thisNewName = newSymbolNames[j];
if (thisNewName.replace(endSuffixRx, "") == thisOriginalName.replace(endSuffixRx, "")) {
latestCopyName = getLatestSymbolCopyName(originalSymbolNames, thisNewName);
selectedSymbolNames.push(latestCopyName);
continue;
}
}
}
var symbolToPlace, symbolToPlaceName, dynamicIndex;
var thisSelectedArt, replacingArt;
var replacingItemUuids = [];
for (var i = sel.length - 1; i > -1; i--) {
thisSelectedArt = sel[i];
dynamicIndex = Math.floor(Math.random() * selectedSymbolNames.length);
symbolToPlaceName = selectedSymbolNames[dynamicIndex];
symbolToPlace = sym.getByName(symbolToPlaceName);
if (thisSelectedArt.typename == "SymbolItem") { // selected item is a symbol: replace the symbol.
replaceSymbolReference(thisSelectedArt, symbolToPlace);
} else if (thisSelectedArt.typename == "GroupItem" && thisSelectedArt.pageItems.length == 1) {
if (thisSelectedArt.symbolItems.length == 1) {
replaceSymbolReference(thisSelectedArt.symbolItems[0], symbolToPlace);
} else {
replacingArt = replaceDocumentArt(doc, thisSelectedArt.pageItems[0], symbolToPlace);
replacingItemUuids.push(replacingArt.uuid);
}
} else {
replacingArt = replaceDocumentArt(doc, thisSelectedArt, symbolToPlace);
replacingItemUuids.push(replacingArt.uuid);
}
}
var thisItem;
for (var i = 0; i < replacingItemUuids.length; i++) {
thisItem = doc.getPageItemFromUuid(replacingItemUuids[i]);
thisItem.selected = true;
}
};
test();
ANd here's the action file
/version 3
/name [ 20
4475706c69636174652053796d626f6c20536574
]
/isOpen 1
/actionCount 1
/action-1 {
/name [ 16
4475706c69636174652053796d626f6c
]
/keyIndex 0
/colorIndex 0
/isOpen 1
/eventCount 1
/event-1 {
/useRulersIn1stQuadrant 0
/internalName (ai_plugin_symbol_palette)
/localizedName [ 7
53796d626f6c73
]
/isOpen 1
/isOn 1
/hasDialog 0
/parameterCount 1
/parameter-1 {
/key 1835363957
/showInPalette -1
/type (enumerated)
/name [ 16
4475706c69636174652053796d626f6c
]
/value 4
}
}
}
Copy link to clipboard
Copied
Wow! Thank you. I will give it a shot.