質問
Guide maker to support range of units help
Hello, I am struggling to make this incorportate units say if a user types 20px or 30pt or 60cm etc
Also it spits out an xml file to the document folder from which it can read past settings a user inputed, this would need to also read say 20px et
Help on this would be most useful
Best
Smyth

/**
* Illustrator Margins, Grid & Baseline Script [Mac-Ready]
* No ES6 code—fully ExtendScript compatible. Tested on Mac.
*/
var settingsXMLPath = Folder.myDocuments + "/IllustratorGridSettings.xml";
// --- XML functions ---
function loadSettingsFromXML(xmlFilePath, abIdx, defaults) {
var file = new File(xmlFilePath);
if (!file.exists) return defaults;
file.open('r');
var content = file.read();
file.close();
var abTag = new RegExp('<Artboard index="' + abIdx + '">([\\s\\S]*?)<\\/Artboard>');
var found = content.match(abTag);
if (found) {
var vals = {};
var tags = ["Top","Bottom","Left","Right","Columns","Rows","VertGutter","HorGutter","BaselineStart","BaselineInc"];
for (var i=0;i<tags.length;i++) {
var tag = new RegExp('<'+tags[i]+'>((.|\\n|\\r)*?)<\\/'+tags[i]+'>');
var t = found[1].match(tag);
vals[tags[i]] = t ? parseFloat(t[1]) : defaults[tags[i]];
}
return vals;
}
return defaults;
}
function saveSettingsToXML(xmlFilePath, abIdx, newVals) {
var file = new File(xmlFilePath);
var xmlContent = '';
if (file.exists) {
file.open('r');
xmlContent = file.read();
file.close();
}
var abTag = new RegExp('<Artboard index="' + abIdx + '">([\\s\\S]*?)<\\/Artboard>','g');
xmlContent = xmlContent.replace(abTag, '');
var abXML = ' <Artboard index="' + abIdx + '">\n';
for (var key in newVals) {
abXML += ' <' + key + '>' + newVals[key] + '</' + key + '>\n';
}
abXML += ' </Artboard>\n';
if (xmlContent.indexOf('<GridSettings>') === -1) {
xmlContent = '<GridSettings>\n' + abXML + '</GridSettings>';
} else {
xmlContent = xmlContent.replace('</GridSettings>', abXML + '</GridSettings>');
}
file.open('w');
file.write(xmlContent);
file.close();
}
// --- Helpers ---
function mmToPt(mm) { return mm * 2.83465; }
function ptToMm(pt) { return pt / 2.83465; }
function makeRGB(r, g, b) {
var color = new RGBColor();
color.red = r; color.green = g; color.blue = b;
return color;
}
function findLayer(doc, name) {
for (var i = 0; i < doc.layers.length; i++) {
if (doc.layers[i].name === name) return doc.layers[i];
}
return null;
}
function deleteLayerByExactName(doc, name) {
for (var i = doc.layers.length - 1; i >= 0; i--) {
if (doc.layers[i].name === name) {
doc.layers[i].locked = false;
doc.layers[i].visible = true;
doc.layers[i].remove();
}
}
}
function removePathsForArtboard(layer, abIdx) {
var abTag = " ab" + abIdx + " ";
for (var i = layer.pathItems.length - 1; i >= 0; i--) {
var p = layer.pathItems[i];
if (p.note && p.note.indexOf(abTag) === 0) p.remove();
}
}
// --- Guide Creation (with per-artboard tagging for merged layers) ---
function addMarginsAndColumnsToLayer(layer, ab, abIdx, top_mm, bottom_mm, left_mm, right_mm, columns, vertGutter_mm, rows, horGutter_mm) {
var rect = ab.artboardRect;
var left = rect[0], top = rect[1], right = rect[2], bottom = rect[3];
var width = right - left, height = top - bottom;
var top_pt = mmToPt(top_mm), bottom_pt = mmToPt(bottom_mm), left_pt = mmToPt(left_mm), right_pt = mmToPt(right_mm);
var vertGutter_pt = mmToPt(vertGutter_mm), horGutter_pt = mmToPt(horGutter_mm);
var abTag = " ab" + abIdx + " ";
// Margin rectangle
var path = layer.pathItems.rectangle(
top - top_pt,
left + left_pt,
width - left_pt - right_pt,
height - top_pt - bottom_pt
);
path.stroked = true;
path.strokeColor = makeRGB(224, 0, 255);
path.strokeWidth = 0.1;
path.filled = false;
path.guides = true;
path.note = abTag + "margin";
// Columns as guides
var gridColor = makeRGB(0, 176, 255);
if (columns > 1) {
var usableWidth = width - left_pt - right_pt;
var colWidth = (usableWidth - (columns - 1) * vertGutter_pt) / columns;
var x = left + left_pt;
for (var c = 0; c < columns - 1; c++) {
x += colWidth;
var vGuide1 = layer.pathItems.add();
vGuide1.setEntirePath([[x, top - top_pt], [x, bottom + bottom_pt]]);
vGuide1.stroked = true; vGuide1.strokeColor = gridColor; vGuide1.strokeWidth = 0.1; vGuide1.filled = false;
vGuide1.guides = true;
vGuide1.note = abTag + "colg";
x += vertGutter_pt;
var vGuide2 = layer.pathItems.add();
vGuide2.setEntirePath([[x, top - top_pt], [x, bottom + bottom_pt]]);
vGuide2.stroked = true; vGuide2.strokeColor = gridColor; vGuide2.strokeWidth = 0.1; vGuide2.filled = false;
vGuide2.guides = true;
vGuide2.note = abTag + "colg";
}
}
// Rows as guides
if (rows > 1) {
var usableHeight = height - top_pt - bottom_pt;
var rowHeight = (usableHeight - (rows - 1) * horGutter_pt) / rows;
var y = top - top_pt;
for (var r = 0; r < rows - 1; r++) {
y -= rowHeight;
var hGuide1 = layer.pathItems.add();
hGuide1.setEntirePath([[left + left_pt, y], [right - right_pt, y]]);
hGuide1.stroked = true; hGuide1.strokeColor = gridColor; hGuide1.strokeWidth = 0.1; hGuide1.filled = false;
hGuide1.guides = true; hGuide1.note = abTag + "rowg";
y -= horGutter_pt;
var hGuide2 = layer.pathItems.add();
hGuide2.setEntirePath([[left + left_pt, y], [right - right_pt, y]]);
hGuide2.stroked = true; hGuide2.strokeColor = gridColor; hGuide2.strokeWidth = 0.1; hGuide2.filled = false;
hGuide2.guides = true; hGuide2.note = abTag + "rowg";
}
}
}
function addBaselineGridToLayer(layer, ab, abIdx, top_mm, bottom_mm, left_mm, right_mm, baselineStart_mm, baselineInc_pt) {
var rect = ab.artboardRect;
var left = rect[0], top = rect[1], right = rect[2], bottom = rect[3];
var top_pt = mmToPt(top_mm), bottom_pt = mmToPt(bottom_mm), left_pt = mmToPt(left_mm), right_pt = mmToPt(right_mm);
var baselineStart_pt = mmToPt(baselineStart_mm);
var abTag = " ab" + abIdx + " ";
var y0 = top - top_pt - baselineStart_pt;
var yEnd = bottom + bottom_pt;
while (y0 > yEnd) {
var line = layer.pathItems.add();
line.setEntirePath([[left + left_pt, y0], [right - right_pt, y0]]);
line.stroked = true;
line.strokeColor = makeRGB(80, 80, 80);
line.strokeWidth = 0.05;
line.filled = false;
line.guides = true;
line.note = abTag + "baseline";
y0 -= baselineInc_pt;
}
}
// --- UI Dialog (always merged mode) ---
function showMarginsDialog() {
if (app.documents.length === 0) { alert("Please open a document first."); return; }
var doc = app.activeDocument;
var abIdx = doc.artboards.getActiveArtboardIndex();
var defaults = {
Top:12.7, Bottom:12.7, Left:12.7, Right:12.7, Columns:2, Rows:2,
VertGutter:4.233, HorGutter:4.233, BaselineStart:0, BaselineInc:12
};
var settings = loadSettingsFromXML(settingsXMLPath, abIdx, defaults);
var w = new Window("dialog", "Margins, Grid & Baseline (for Artboard " + (abIdx + 1) + ")");
w.orientation = "column";
w.alignChildren = "left";
w.spacing = 10;
var marginPanel = w.add("panel", undefined, "Margins (mm)");
marginPanel.orientation = "column";
marginPanel.alignChildren = "left";
marginPanel.margins = 12;
var mRow1 = marginPanel.add("group");
mRow1.orientation = "row";
mRow1.alignChildren = "center";
mRow1.add("statictext", undefined, "Top:");
var topInput = mRow1.add("edittext", undefined, settings.Top);
topInput.characters = 5;
mRow1.add("statictext", undefined, "mm Left:");
var leftInput = mRow1.add("edittext", undefined, settings.Left);
leftInput.characters = 5;
mRow1.add("statictext", undefined, "mm");
var mRow2 = marginPanel.add("group");
mRow2.orientation = "row";
mRow2.alignChildren = "center";
mRow2.add("statictext", undefined, "Bottom:");
var bottomInput = mRow2.add("edittext", undefined, settings.Bottom);
bottomInput.characters = 5;
mRow2.add("statictext", undefined, "mm Right:");
var rightInput = mRow2.add("edittext", undefined, settings.Right);
rightInput.characters = 5;
mRow2.add("statictext", undefined, "mm");
var gridPanel = w.add("panel", undefined, "Grid");
gridPanel.orientation = "row";
gridPanel.alignChildren = "center";
gridPanel.margins = 12;
gridPanel.spacing = 10;
gridPanel.add("statictext", undefined, "Columns:");
var colInput = gridPanel.add("edittext", undefined, settings.Columns);
colInput.characters = 3;
gridPanel.add("statictext", undefined, "Vertical Gutter:");
var vertGutterInput = gridPanel.add("edittext", undefined, settings.VertGutter);
vertGutterInput.characters = 5;
gridPanel.add("statictext", undefined, "mm");
gridPanel.add("statictext", undefined, "Rows:");
var rowInput = gridPanel.add("edittext", undefined, settings.Rows);
rowInput.characters = 3;
gridPanel.add("statictext", undefined, "Horizontal Gutter:");
var horGutterInput = gridPanel.add("edittext", undefined, settings.HorGutter);
horGutterInput.characters = 5;
gridPanel.add("statictext", undefined, "mm");
var basePanel = w.add("panel", undefined, "Baseline Grid");
basePanel.orientation = "row";
basePanel.alignChildren = "center";
basePanel.margins = 12;
basePanel.spacing = 10;
basePanel.add("statictext", undefined, "Start:");
var baselineStartInput = basePanel.add("edittext", undefined, settings.BaselineStart);
baselineStartInput.characters = 5;
basePanel.add("statictext", undefined, "mm Increment:");
var baselineIncInput = basePanel.add("edittext", undefined, settings.BaselineInc);
baselineIncInput.characters = 5;
basePanel.add("statictext", undefined, "pt");
var applyAllGroup = w.add("group");
applyAllGroup.orientation = "row";
var applyAllChk = applyAllGroup.add("checkbox", undefined, "Apply to all artboards");
applyAllChk.value = (doc.artboards.length === 1);
var btnGroup = w.add("group");
btnGroup.orientation = "row";
btnGroup.alignment = "right";
btnGroup.add("button", undefined, "Cancel", { name: "cancel" });
var okBtn = btnGroup.add("button", undefined, "OK", { name: "ok" });
okBtn.onClick = function() {
var top = parseFloat(topInput.text), bottom = parseFloat(bottomInput.text),
leftVal = parseFloat(leftInput.text), rightVal = parseFloat(rightInput.text),
cols = parseInt(colInput.text), rows = parseInt(rowInput.text),
vertGutter = parseFloat(vertGutterInput.text), horGutter = parseFloat(horGutterInput.text),
baselineStart = parseFloat(baselineStartInput.text), baselineInc = parseFloat(baselineIncInput.text);
if (
isNaN(top) || isNaN(bottom) || isNaN(leftVal) || isNaN(rightVal) ||
isNaN(cols) || isNaN(rows) ||
isNaN(vertGutter) || isNaN(horGutter) ||
isNaN(baselineStart) || isNaN(baselineInc) ||
top < 0 || bottom < 0 || leftVal < 0 || rightVal < 0 ||
cols < 0 || rows < 0 ||
vertGutter < 0 || horGutter < 0 ||
baselineInc <= 0
) {
alert("Please enter valid (positive) numbers. Columns and Rows and gutters can be 0 or more, Increment > 0.");
return;
}
function checkGridFit(abIdx, top, bottom, leftVal, rightVal, cols, rows, vertGutter, horGutter) {
var rect = doc.artboards[abIdx].artboardRect;
var artboardW = rect[2] - rect[0] - mmToPt(leftVal) - mmToPt(rightVal);
var artboardHmm = rect[1] - rect[3] - mmToPt(top) - mmToPt(bottom);
var mmW = ptToMm(artboardW), mmH = ptToMm(artboardHmm);
var minColWidth = 1, minRowHeight = 1;
var failCol = false, failRow = false;
if (cols > 1) {
var totalColGutters = (cols - 1) * vertGutter;
var usable = mmW - totalColGutters;
if (usable <= 0 || (usable/cols) < minColWidth) { failCol = true; }
}
if (rows > 1) {
var totalRowGutters = (rows - 1) * horGutter;
var usable = mmH - totalRowGutters;
if (usable <= 0 || (usable/rows) < minRowHeight) { failRow = true; }
}
return {failCol: failCol, failRow: failRow};
}
var abIndices = [];
if (applyAllChk.value) {
for (var i = 0; i < doc.artboards.length; i++) abIndices.push(i);
} else {
abIndices.push(abIdx);
}
var vertGutterOverride = {}, horGutterOverride = {};
var warnedCol = false, warnedRow = false;
for (var i=0; i<abIndices.length; i++) {
var check = checkGridFit(abIndices[i], top, bottom, leftVal, rightVal, cols, rows, vertGutter, horGutter);
if (check.failCol) {
if (!warnedCol) alert("Your column/gutter combination cannot fit on at least one artboard. Vertical gutter is being reset to the default.");
vertGutterOverride[abIndices[i]] = defaults.VertGutter;
warnedCol = true;
}
if (check.failRow) {
if (!warnedRow) alert("Your row/gutter combination cannot fit on at least one artboard. Horizontal gutter is being reset to the default.");
horGutterOverride[abIndices[i]] = defaults.HorGutter;
warnedRow = true;
}
}
// --- Always merge guides into single layers ---
if (applyAllChk.value) {
deleteLayerByExactName(doc, "Margins and Columns");
deleteLayerByExactName(doc, "Baseline");
}
var marginsLayer = findLayer(doc, "Margins and Columns");
if (!marginsLayer) { marginsLayer = doc.layers.add(); marginsLayer.name = "Margins and Columns"; }
marginsLayer.locked = false; marginsLayer.visible = true;
var baselineLayer = findLayer(doc, "Baseline");
if (!baselineLayer) { baselineLayer = doc.layers.add(); baselineLayer.name = "Baseline"; }
baselineLayer.locked = false; baselineLayer.visible = true;
for (var k = 0; k < abIndices.length; k++) {
var idx = abIndices[k];
var thisVertGutter = vertGutterOverride[idx] !== undefined ? vertGutterOverride[idx] : vertGutter;
var thisHorGutter = horGutterOverride[idx] !== undefined ? horGutterOverride[idx] : horGutter;
var ab = doc.artboards[idx];
if (applyAllChk.value) {
// Already wiped, so no selective deletion required
} else {
removePathsForArtboard(marginsLayer, idx);
removePathsForArtboard(baselineLayer, idx);
}
addMarginsAndColumnsToLayer(marginsLayer, ab, idx, top, bottom, leftVal, rightVal, cols, thisVertGutter, rows, thisHorGutter);
addBaselineGridToLayer(baselineLayer, ab, idx, top, bottom, leftVal, rightVal, baselineStart, baselineInc);
saveSettingsToXML(settingsXMLPath, idx, {
Top: top, Bottom: bottom, Left: leftVal, Right: rightVal,
Columns: cols, Rows: rows, VertGutter: thisVertGutter, HorGutter: thisHorGutter,
BaselineStart: baselineStart, BaselineInc: baselineInc
});
}
marginsLayer.locked = true; baselineLayer.locked = true;
w.close();
};
w.center(); w.show();
}
showMarginsDialog();