Copy link to clipboard
Copied
So I've been using a hand made script for years and years now, it's actually a set of 2 scripts.
Script 1 "#LogAllDimensions-Alt.js" does what it says on the tin, it logs the Tranformation data like this:
"X_POS_0;Y_POS_0;WIDTH_0;HEIGHT_0$X_POS_1;Y_POS_1;WIDTH_1;HEIGHT_1$", it then shows a prompt containing the string however long it may be.
Then I can start selecting different objects and run Script 2: "#PositionObjectsBasedOnLog.js"
This does the opposite and splits the string at every "$" since those are dividers for each set of transformation data, then it splits each of those at ";" so that I get the raw X, Y, WIDTH, HEIGHT properties,
which are then used to reposition and resize my current selection accordingly.
I used to work at a printing company and I had to make efficient layouts when printing things so we don't waste more material than needed, but whenever we had to deal with extremely heavy images this got time consuming.
I made these scripts as a work around, I'd first use rectangles with the exact size as the images we'd need to print, I'd then puzzle together the layout and once that was figured out I only needed to place the actual images, make enough copies, select them and paste in the coordinates to set their new transformation data.
However at that company I worked on Macs, but now that I work elsewhere on a windows PC, some issues have arisen with "#PositionObjectsBasedOnLog.js"
When I paste in the transformation string it processes a couple of them only to then stop and spit out an error partway through.
No changes were made to this script between using it on Mac and Windows.
The weird thing is that if I edit the script and paste my string directly into it, then it works just fine, but if done through entering it into the prompt, this issue occurs.
Script 1 "#LogAllDimensions.js":
app.preferences.setBooleanPreference("ShowExternalJSXWarning", false);
var myDocument = app.activeDocument;
var convUnit = 2.834645;
var mySelection = new Object;
selections = myDocument.selection;
var stringToAlert = "";
for(i=0;i<selections.length;i++){
mySelection = myDocument.selection[i];
stringToAlert = (stringToAlert + (mySelection.left / convUnit) + ";" + (mySelection.top / convUnit) + ";" + (mySelection.width / convUnit) + ";" + (mySelection.height / convUnit) + "$");
if(i==(selections.length - 1)){
alertUser();
}
}
function alertUser(){
prompt("Transformation Data for " + selections.length + " Objects:", stringToAlert);
}
Script 2 "#PositionObjectsBasedOnLog.js":
app.preferences.setBooleanPreference("ShowExternalJSXWarning", false);
var myDocument = app.activeDocument;
var convUnit = 2.834645;
var mySelection = new Object;
selections = myDocument.selection;
var stringValue = (prompt("Input Log Text Here:", ""));
var livePreviewEnabled = true;
var resizingEnabled = true;
var scaleMultiplier = 1;
for(i=0;i<selections.length;i++){
mySelection = myDocument.selection[i];
var splitString = stringValue.split("$");
var splitStringValues = splitString[i].split(";");
var leftPos = (parseFloat(splitStringValues[0]) * convUnit);
var topPos = (parseFloat(splitStringValues[1]) * convUnit);
var objWidth = (parseFloat(splitStringValues[2]) * convUnit);
var objHeight = (parseFloat(splitStringValues[3]) * convUnit);
//Disabled section for automatically rotating objects if it considers the width and height to be swapped.
//This does work, but is extremely senstive to a difference of even 0.0000000001, so I had to disable it for now.
/*
if(objHeight > objWidth && mySelection.height < mySelection.width){
mySelection.rotate(90);
}
if(objWidth > objHeight && mySelection.width < mySelection.height){
mySelection.rotate(90);
}
*/
mySelection.left = (leftPos * scaleMultiplier);
mySelection.top = (topPos * scaleMultiplier);
if(resizingEnabled==true){
mySelection.width = (objWidth * scaleMultiplier);
mySelection.height = (objHeight * scaleMultiplier);
}
if(livePreviewEnabled==true){
app.redraw();
}
}
Note: I'm no JS Expert, so excuse me if I'm handling things a bit inefficient.
Though do tell me because I'm curious to know how it could be done better.
Copy link to clipboard
Copied
Also the convUnit thing you see everywhere is to convert back and forth between Illustrator's internal unit system and millimeters since I can't directly tell the script to interpret values as mm
Copy link to clipboard
Copied
Could you show us the error you get? And even better, post a sample document? (Save as pdf, Illustrator editable). I might not be able to help because I use MacOS but it will be easier for someone else to test on Windows.
- Mark
PS: a tip—just call your `convUnit` mm, its much easier to understand:
const mm = 2.834645;
var doc = app.activeDocument;
var tf = doc.textFrames.add();
tf.contents = doc.name;
tf.top = 10 * mm;
tf.left = 5 * mm;
or look at the built-in UnitValue object which handles unit conversions in a more formal way, but I don't usually bother with, personally.
Copy link to clipboard
Copied
Fair points, basically it complains about a closing curly bracket on line 42 as it seems to be trying to interpret that as data.
Which is weird as heck because although } is indeed not a numeric value, it should not be attempting to read that in the first place
Copy link to clipboard
Copied
I've made a quick recording that goes through the process from start to finish, hope it helps
Copy link to clipboard
Copied
Hi @ict-opr I suspect the copy/pasting is adding something strange to the text string, maybe an invisible character, and I would try filtering the string to remove anything that isn't an expected character—let me know if you want to do that.
But, just for learning, I've written a version of your scripts combined into a single palette. It should—hopefully!— remove the error you are seeing because it doesn't do the string copy/pasting that your current workflow uses. I hope it will be useful, at least as a starting point. I apologize for the mess of BridgeTalk nonsense in the script but that is just what we have to do to use a palette, as opposed to a dialog.
Let me know how it goes.
- Mark
/**
* @file Position Items.js
*
* Variation of user @ict-opr's two scripts
* showing use of palette to load positions
* and later use them to position items.
*
* @author m1b
* @version 2025-09-26
* @discussion https://community.adobe.com/t5/illustrator-discussions/scripting-issue-that-only-occurs-on-windows/m-p/15520320
*/
//@targetengine 'positionItems'
(function () {
// check if the window already exists by using a global variable
if (
"undefined" !== typeof $.global.palette
&& null !== $.global.palette
) {
// NOTE: while debugging, you will want to disable this part
// because it will stop your new palette from instantiating
// (otherwise you'll need to restart Illustrator each time!)
$.global.palette.active = true;
$.global.palette.show();
return;
}
// create a new ScriptUI palette (modeless window)
$.global.palette = new Window("palette", "Position Items", undefined, { resizeable: false });
const FIELD_DELIMITER = ';';
const ITEM_DELIMITER = '$';
var activePositions = '';
var buttons = palette.add('group {orientation: "row", alignment:["fill","top"], alignChildren:["fill","top"] }');
// var loadGroup = buttons.add('group {orientation: "column", alignChildren:["left","top"] }');
var loadButton = buttons.add('button { text:"Load" }');
// var positionGroup = buttons.add('group {orientation: "row", alignChildren:["left","top"] }');
var positionButton = buttons.add('button { text:"Position" }');
var loadedLabel = palette.add('statictext {text:"", alignment:["fill","top"], justify:"center" }');
var resizeCheckbox = buttons.add('checkbox {text:"Resize Items", alignment:["fill","bottom"] }');
/** load button is clicked - send `loadPositions` function to Illustrator */
loadButton.onClick = function () {
// a BridgeTalk message
var bt = new BridgeTalk();
bt.target = "illustrator";
// convert the function to a string IIFE
// this is a way to send code via bridgeTalk
bt.body = "(" + loadPositions.toSource() + ")(#I,#F);"
// include string parameters
.replace('#I', '"' + ITEM_DELIMITER + '"')
.replace('#F', '"' + FIELD_DELIMITER + '"');
// handle the result returned from Illustrator
bt.onResult = function (response) {
activePositions = response.body || '';
updateUI();
};
// send the script to Illustrator
bt.send();
};
/** position button is clicked - send `positionItems` function to Illustrator */
positionButton.onClick = function () {
// a BridgeTalk message
var bt = new BridgeTalk();
bt.target = "illustrator";
// convert the function to a string IIFE
// this is a way to send code via bridgeTalk
bt.body = "(" + positionItems.toSource() + ")(#P,#R,#I,#F);"
// include string parameters
.replace('#P', '"' + activePositions + '"')
.replace('#R', '"' + (resizeCheckbox.value ? '1' : '') + '"')
.replace('#I', '"' + ITEM_DELIMITER + '"')
.replace('#F', '"' + FIELD_DELIMITER + '"');
// send the script to Illustrator
bt.send();
};
// show the palette
updateUI();
palette.center();
palette.show();
/** update the UI - positions count and button enabling */
function updateUI() {
var positionCount = (activePositions.split(ITEM_DELIMITER).length - 1);
loadedLabel.text = positionCount + ' positions ready.';
positionButton.enabled = positionCount > 0;
resizeCheckbox.enabled = positionCount > 0;
};
/**
* Returns a `positions` string from selected objects.
* To be sent to Illustrator via BridgeTalk
* @param {String} itemDelimiter - string to add between item position strings.
* @param {String} fieldDelimiter - string to add between fields of an item position string.
* @returns {String} - the position(s).
*/
function loadPositions(itemDelimiter, fieldDelimiter) {
/*
IMPORTANT: you must use block comments in any function
that you will be sending via BridgeTalk, because it seems
to evaluate the whole body as a single line, therefore
an inline comment will nullify everything after it.
*/
if (0 === app.documents.length)
return alert("Please open a document and try again.");
var doc = app.activeDocument;
var items = doc.selection;
if (0 === items.length)
return alert("Please select some page items and try again.");
var positions = '';
/* build the positions string */
for (var i = 0, item; i < items.length; i++) {
item = items[i];
positions += [item.left, item.top, item.width, item.height].join(fieldDelimiter) + itemDelimiter;
}
return positions;
};
/**
* Positions selected items according
* to `activePositions` string.
* To be sent to Illustrator via BridgeTalk
* @param {String} positions - the positions to use.
* @param {String} [resize] - whether to resize the item (default: do not resize).
* @param {String} itemDelimiter - string to add between item position strings.
* @param {String} fieldDelimiter - string to add between fields of an item position string.
*/
function positionItems(positions, resize, itemDelimiter, fieldDelimiter) {
/*
IMPORTANT: you must use block comments in any function
that you will be sending via BridgeTalk, because it seems
to evaluate the whole body as a single line, therefore
an inline comment will nullify everything after it.
*/
var scaleMultiplier = 1;
if (0 === app.documents.length)
return alert("Please open a document and try again.");
var doc = app.activeDocument;
var items = doc.selection;
if (0 === items.length)
return alert("Please select some page items and try again.");
positions = positions.split(itemDelimiter);
var len = Math.min(positions.length, items.length);
/* position the items */
for (var i = 0, item, position; i <= len; i++) {
item = items[i];
position = positions[i].split(fieldDelimiter);
var leftPos = Number(position[0]);
var topPos = Number(position[1]);
var objWidth = Number(position[2]);
var objHeight = Number(position[3]);
item.left = leftPos * scaleMultiplier;
item.top = topPos * scaleMultiplier;
if (resize) {
item.width = (objWidth * scaleMultiplier);
item.height = (objHeight * scaleMultiplier);
}
}
};
})();
Copy link to clipboard
Copied
Try running the script straight from the Scripts Menu, skip the Script Panel to see if it works.
Find more inspiration, events, and resources on the new Adobe Community
Explore Now