Skip to content

Instantly share code, notes, and snippets.

@creold
Last active March 12, 2024 13:24
Show Gist options
  • Save creold/c6fbad64b836d3d610b0f1c19996e42a to your computer and use it in GitHub Desktop.
Save creold/c6fbad64b836d3d610b0f1c19996e42a to your computer and use it in GitHub Desktop.
/*
Make highlighting rectangle based on size of TextFrame
Discussion: https://community.adobe.com/t5/illustrator-discussions/script-make-rectangle-based-on-size-of-object-on-layer/td-p/13383600
Author: Sergey Osokin, email: hi@sergosokin.ru
Check my other scripts: https://github.com/creold
Donate (optional):
If you find this script helpful, you can buy me a coffee
- via Buymeacoffee: https://www.buymeacoffee.com/aiscripts
- via Donatty https://donatty.com/sergosokin
- via DonatePay https://new.donatepay.ru/en/@osokin
- via YooMoney https://yoomoney.ru/to/410011149615582
*/
//@target illustrator
app.preferences.setBooleanPreference('ShowExternalJSXWarning', false); // Fix drag and drop a .jsx file
function main() {
if (!documents.length) return;
if (!selection.length || selection[0].typename !== 'TextFrame') return;
polyfills();
var ratioW = 0.5 // Width scale
var ratioH = 0.5 // Height scale
var isXHeight = false;
var color = new RGBColor();
color.red = 255;
color.green = 235;
color.blue = 0;
var inp = prompt('Enter parameters:\nwidth scale ratio (decimal),\nheight: x-height (x) or cap height (c)', ratioW + ',' + ratioH + 'c', 'Highlight Text');
if (!inp.length || inp !== null) {
inp = inp.split(',');
if (!isNaN(inp[0])) ratioW = parseFloat(inp[0]);
if (/x/i.test(inp[1]) == 'x') isXHeight = true;
else if (/c/i.test(inp[1]) == 'x') isXHeight = false;
if (!isNaN(parseFloat(inp[1]))) ratioH = parseFloat(inp[1]);
}
var tfs = getTextFrames(selection);
var rects = [];
tfs.forEach(function (e) {
if (e.lines.length > 1) {
var lines = divide(e.layer, e);
lines.forEach(function (l) {
rects = rects.concat(drawHighlightRect(l, color, ratioW, ratioH, isXHeight, e));
});
// Remove line-breaking TextFrame
for (var i = lines.length - 1; i >= 0; i--) {
lines[i].remove();
}
} else {
rects.push(drawHighlightRect(e, color, ratioW, ratioH, isXHeight));
}
});
if (rects.length) selection = rects;
}
// Setup JavaScript Polyfills
function polyfills() {
Array.prototype.forEach = function (callback, startPos, inc) {
startPos = startPos || 0;
inc = inc || 1;
for (var i = startPos; i < this.length; i += inc)
callback(this[i], i, this);
};
}
// Get TextFrames array from collection
function getTextFrames(coll) {
var tfs = [];
for (var i = 0, len = coll.length; i < len; i++) {
if (/text/i.test(coll[i].typename)) tfs.push(coll[i]); // coll[i].kind == TextType.POINTTEXT
else if (/group/i.test(coll[i].typename)) tfs = tfs.concat(getTextFrames(coll[i].pageItems));
}
return tfs;
}
function drawHighlightRect(tf, color, ratioW, ratioH, isX, dest) {
if (arguments.length == 4 || !dest) dest = tf;
selection = null;
tf.selected = true;
var coords = getCoords(tf, ratioW, isX);
var rect = tf.layer.pathItems.rectangle(coords.t - (0.5 * (1 - ratioH) * coords.h), coords.l, coords.w * ratioW, ratioH * coords.h);
rect.fillColor = color;
rect.stroked = false;
rect.move(dest, ElementPlacement.PLACEAFTER);
return rect;
}
function getCoords(obj, ratioW, isX) {
var dup = obj.duplicate().createOutline();
var bnds = dup.geometricBounds;
var w = dup.width;
dup.remove();
var left = bnds[0] + w * 0.5 * (1 - ratioW);
dup = obj.duplicate();
dup.contents = isX ? 'x' : 'X';
dup.createOutline();
var h = selection[0].height;
var top = selection[0].geometricBounds[1];
selection[0].remove();
return { 't': top, 'l': left, 'w': w, 'h': h };
}
// https://community.adobe.com/t5/illustrator-discussions/break-text-area-into-text-lines/m-p/5258096
function divide(relObj, item) {
//getObject justification and leading
var justification = item.textRange.justification;
var vSpacing = item.textRange.leading;
var tfTop = item.top;
var tfLeft = item.left;
var newTF;
var out = [];
for (var j = 0; j < item.lines.length; j++) {
newTF = relObj.textFrames.add();
newTF.move(item, ElementPlacement.PLACEBEFORE);
item.characters[0].duplicate(newTF.insertionPoints[0]);
newTF.contents = item.lines[j].contents;
newTF.top = tfTop;
tfTop -= vSpacing;
switch (justification) {
case (Justification.CENTER):
newTF.left = (tfLeft + (item.width / 2)) - (newTF.width / 2);
break;
case (Justification.RIGHT):
newTF.left = (tfLeft + item.width) - newTF.width;
break;
default:
newTF.left = item.left;
}
out.push(newTF);
newTF.textRange.justification = justification;
}
return out;
}
// Run script
try {
main();
} catch (e) { }
@creold
Copy link
Author

creold commented Feb 3, 2023

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment