Copy link to clipboard
Copied
Hi! I'm extremely new to scripting for Illustrator, and to JS in general, but here's my use case: I write documentation in DITA, which gets translated into multiple languages. In order to translate image text, we wrap images <img> and text <p> inside <fig> tags, and use scripts to import and initialize those variables. Each language is shown in the Variables window as a data set, so we can manually check to make sure everything looks right in all languages. These images are all black-and-white line drawings, and are imported to a single layer ("Layer 1").
We've started running into issues with transparency--Illustrator displays everything against a white background, but the artboard is actually transparent, so unless you set a fill for your objects or manually place a white background layer, your objects don't display well against darker backgrounds. We've got thousands of images, and it's impossible to fix this manually. I'm looking to modify our import/initialize scripts to create a rectangle with a white fill (#FFFFFF) and empty stroke, using the same dimensions as the <Linked File> variable, and send that shape to the back, either within the existing layer, or by creating a new layer.
importVariables();
initVariables();
function importVariables() {
#target illustrator
//var variableLibraryDir = "W:\\xina\\svg-variable-libraries";
var variableLibraryDir = "\\\\ns-ni1\\xina\\variable-libraries";
//var variableLibraryDir = "C:\\Users\\dbadger\\Desktop\\Shure SVG";
var doc = app.activeDocument;
var docname = (doc.name.split('.'))[0]; // name without extension
var varLib = variableLibraryDir + "\\" + docname + ".xml";
doc.importVariables(File(varLib));
}
function initVariables() {
#target illustrator
var doc = app.activeDocument;
var docname = (doc.name.split('.'))[0]; // name without extension
var extension = (doc.name.split('.'))[1];
//user must open variable library manually the first time
var vars = doc.variables;
var flipMatrix = app.getScaleMatrix(100,-100);
var artBoardPosition = doc.artboards[0].rulerOrigin;
for (var i = 0; i < vars.length; i++){
var type = vars[i].kind;
var pageItems = vars[i].pageItems.length;
if(pageItems == 0){
if(type == VariableKind.TEXTUAL){
//create textobject and associate with this variable
var textRef = doc.textFrames.add();
textRef.position = artBoardPosition;
textRef.contentVariable = vars[i];
//doc.textFrames.appliedFont = app.fonts.item(NimbusSansGlobal);
}
else if(type == VariableKind.IMAGE){
//create graphic object and associate with this variable
var graphicRef = doc.placedItems.add();
graphicRef.position = artBoardPosition;
var graphicPath = vars[i];
graphicRef.contentVariable = graphicPath;
//need to flip vertical - Illustrator Bug?
graphicRef.transform(flipMatrix);
}
else{}
}
}
var ds = doc.dataSets;
for (var j = 0; j < ds.length; j++){
var thisLang = ds[j].name;
if(thisLang == 'en-US' || thisLang == 'ENG'){
ds[j].display();
redraw();
}
}
var textFrames = doc.textFrames;
var placedItems = doc.placedItems;
var alertString = "The following objects are not associated with a variable: \n";
for (var i = 0; i < textFrames.length; i++){
if(textFrames[i].contentVariable == undefined){
alertString = alertString + "\n" + "text: " + textFrames[i].contents;
}
}
for (var i = 0; i < placedItems.length; i++){
if(placedItems[i].contentVariable == undefined){
alertString = alertString + "\n" + "image: " + placedItems[i].file;
}
}
if(alertString != "The following objects are not associated with a variable: \n"){
alert(alertString);
}}
1 Correct answer
Thank you again! I wasn't able to get it working by combining it with an existing function, but your explanations of how all this stuff works made a ton of sense, and after some trial-and-error and picking apart other scripts, I figured out how to get it working.
I ended up adding a new function to the end of the script, which uses the visible bounds of the selected object to establish the dimensions. This function creates a white rectangle the same size as the selection (in my case, the image p
...Explore related tutorials & articles
Copy link to clipboard
Copied
Not as familiar with illustrator variables/datasets but hopefully this will help.
/*
rectangles are drawn off 4 digits
a pair of YX coordinates followed by the Width and the Height from that coordinate
The below example makes a rectangle at [x,y] [3,-5] that is 20 pts wide and 50 pts tall
using -5 for the Y as Y=0 is the top left of the artboard, using positive Y will go above the artboard
*/
var BackgroundRect = app.activeDocument.layers[0].pathItems.rectangle(-5, 3, 20, 50)
/*
in your instance you want the size to be the same as the linked placed item.
whenever you place your image, get that reference and pull the geometricBounds (or top/left/width/height)
var MyImage = app.activeDocument.layers[0].placedItems.add()
MyImage.file = File(ImagePath)
var BackgroundRect = app.activeDocument.layers[0].pathItems.rectangle(MyImage.top, MyImage.left, MyImage.width, MyImage.height)
OR GeoBounds
GeometricBounds are an array of 4 numbers, 2 pairs of x/y coords, the top left and the bottom right
var myGeoBounds = MyImage.geometricBounds //this will return [3,-5,23,-55]
var BackgroundRect = app.activeDocument.layers[0].pathItems.rectangle(myGeoBounds[1], myGeoBounds[0], Math.abs(myGeoBounds[2]-myGeoBounds[0],Math.abs(myGeoBounds[3]-myGeoBounds[1])
we do absolute math to remove the negatives and have to do the X2 coord to the X1 coord to get proper width and same for Height
*/
BackgroundRect.stroked = false;
/* make sure the rectangle does not have a stroke */
BackgroundRect.fillColor = app.activeDocument.swatches.getByName("White").color;
/* apply whatever color fill you want. All AI files should have the basic Registration,[None],White,Black.
If concerned of not having that color you can create it in the script to call
var CMYKWhite = new CMYKColor();
CMYKWhite.cyan = 0;
CMYKWhite.magenta = 0;
CMYKWhite.yellow = 0;
CMYKWhite.black = 0;
BackgroundRect.fillColor = CMYKWhite
*/
BackgroundRect.move(app.activeDocument.layers[0],ElementPlacement.PLACEATEND)
/*
move the rectangle to whever you need it.
WhatImMoving.move(WhereItsGoing,HowItsbeingMoved)
ElementPlacement.INSIDE
ElementPlacement.PLACEAFTER
ElementPlacement.PLACEATBEGINNING
ElementPlacement.PLACEATEND
ElementPlacement.PLACEBEFORE
*/
Copy link to clipboard
Copied
@RobOctopus this is amazingly helpful, thank you so much! I haven't been able to get it to work quite right, but I think I understand what I need to do more clearly.
The white rectangle doesn't need to be associated with a variable, it just needs to get its dimensions from the graphic object created and associated with the linked file variable. The size is not consistent, it depends on the image in question, so I don't want to use specific values; can I have the script find the top/left/width/height values from the graphicRef object created in the initVariables function? Or do I need to follow your initial suggestion and establish a "MyImage" definition based on that object, and use MyImage.top, MyImage.left, etc?
A related question: would creating the background rectangle need to be part of the initVariables function, or would it need to be a separate function that occurs after the graphic object has been created?
Copy link to clipboard
Copied
Right, I'm not quite sure when the graphic is being placed and it's size is being established.
based on your code I would assume somewhere in this bit, it's creating the placedItem object and assigning the variable graphicRef to it, but I've never used contentVariable and am unsure if that is actually assigning an image to it. I've always used the placedItem.File = File(myPath) method of assigning an image.
...
else if(type == VariableKind.IMAGE){
//create graphic object and associate with this variable
var graphicRef = doc.placedItems.add();
graphicRef.position = artBoardPosition;
var graphicPath = vars[i];
graphicRef.contentVariable = graphicPath;
//need to flip vertical - Illustrator Bug?
graphicRef.transform(flipMatrix);
}
...
until the image has been assigned to the placedItem, it doesnt have any size. the PlacedItem simply becomes a container thats incredibly tiny waiting to be loaded with more information. After the graphic is actually assigned to the placedItem, then it has a size that you would want. so my guess is you would want to add all the rectangle creation after the graphicRef.transform line (so to answer your question, it can be apart of the function, not a separate one).
...
graphicRef.transform(flipMatrix);
var myGeoBounds = graphicRef.geometricBounds
/* hopefully get the geo bounds you're looking for */
var BackgroundRect = doc.pathItems.rectangle(myGeoBounds[1], myGeoBounds[0], Math.abs(myGeoBounds[2]-myGeoBounds[0],Math.abs(myGeoBounds[3]-myGeoBounds[1])
/* OR using top/left/width/height */
var BackgroundRect = doc.pathItems.rectangle(graphicRef.top,graphicRef.left,graphicRef.width,graphicRef.height)
/* make that rectangle based on those geoBounds. you can add it wherever you like, here it will add to the same layer the placed image has been added to */
/* rest of the rectangle code for color/stroke/stack */
hope this helps
Copy link to clipboard
Copied
Thank you again! I wasn't able to get it working by combining it with an existing function, but your explanations of how all this stuff works made a ton of sense, and after some trial-and-error and picking apart other scripts, I figured out how to get it working.
I ended up adding a new function to the end of the script, which uses the visible bounds of the selected object to establish the dimensions. This function creates a white rectangle the same size as the selection (in my case, the image pulled in from our variable graphic library), sends it to the back, and locks it.
function makeRect() {
if (selection.length == 0) {
alert("No object …");
return;
}else{
//get dimensions
var myDoc = app.activeDocument;
var Sel = myDoc.selection;
var SelVB = Sel[0].visibleBounds;
var Left = SelVB[0];
var Top = SelVB[1];
var SelWidth = (SelVB[2] - SelVB[0]);
var SelHeight = (SelVB[1] - SelVB[3]);
//create rectangle
var backgroundRect = myDoc.pathItems.rectangle(Top, Left, SelWidth, SelHeight);
backgroundRect.stroked = false;
backgroundRect.fillColor = app.activeDocument.swatches.getByName("White").color;
//send rectangle to background and lock
backgroundRect.move(app.activeDocument.layers[0],ElementPlacement.PLACEATEND);
backgroundRect.locked = true
}
}
}

