m1b
Community Expert
m1b
Community Expert
Activity
‎Jan 10, 2021
08:13 PM
2 Upvotes
Ha ha! var problema = 'solved!';
... View more
‎Jan 10, 2021
08:02 PM
Ah! Yes that was my problem. Thank you Carlos! I've been warned before about doing that before (@femkeblanco!) and I didn't see it this time. I've been using other languages were the idiom is to use the property name as a local variable. I must remember that ExtendScript has very lax variable scoping. - Mark
... View more
‎Jan 10, 2021
06:53 PM
1 Upvote
That looks really cool! I couldn't get the test to run though. The error was "Error Code# 21: undefined is not an object" on this line: if (RayCaster.rayIntersectsSegment(new RayCaster.Point(point[0], point[1]), segment)) { Does it work on your current system? - Mark
... View more
‎Jan 10, 2021
03:17 PM
2 Upvotes
I've done a quick modification to Hiroyuki Sato's Divide script so that it divides paths based on an absolute distance, rather than number of divisions. The result will serve to approximate the curved paths with points approximately every n pts apart, and I hope you might be able to use for your purpose. Here's the modified script: // Divide (length)
// divides each selected segment into specified number. based on the length.
// Length of each segment in each divided segments is equal.
// test env: Adobe Illustrator CS3, CS6 (Windows)
// Copyright(c) 2006 Hiroyuki Sato
// https://github.com/shspage
// This script is distributed under the MIT License.
// See the LICENSE file for details.
// 2018.07.20, modified to ignore locked/hidden objects in a selected group
// 2021.01.11, modified by m1b in attempt to divide paths based on an absolute distance
// "targetSpecifier": "illustrator-25.064"
var ver10 = (version.indexOf('10') == 0);
// Settings ====================
var absoluteDistanceMode = true; // divides a path segment to keep approximately n pts distance between added points
var straightLinesOnlyMode = true; // convert curves to straight lines
var divisionsOrApproximateDistanceBetweenPoints = 10; // in absoluteDistanceMode it is the (approximate) distance between points, measured in pts, otherwise it is the number of divisions
// =============================
main();
function main() {
var paths = [];
getPathItemsInSelection(n, paths);
if (paths.length < 1) return;
var n = divisionsOrApproximateDistanceBetweenPoints; // default dividing number, or in absolute distance mode it is the (approximate) distance between points, measured in pts
// =============================
// not ver.10 : input a number with a prompt box
// if (!ver10) {
// n = prompt("divide each selected segment into ... (based on its length)", n);
// if (!n) {
// return;
// } else if (isNaN(n) || n < 2) {
// alert("Please input a number greater than 1 with 1 byte characters.");
// return;
// }
// n = parseInt(n);
// }
var i, j, k, p, q;
var pnts, len, ar, redrawflg;
for (var h = 0; h < paths.length; h++) {
redrawflg = false;
pnts = [];
p = paths[h].pathPoints;
for (i = 0; i < p.length; i++) {
j = parseIdx(p, i + 1);
if (j < 0) break;
if (!sideSelection(p[i], p[j])) continue;
ar = [i];
q = [p[i].anchor, p[i].rightDirection, p[j].leftDirection, p[j].anchor];
if (absoluteDistanceMode) {
var fullLen = getT4Len(q, 0);
var n2 = Math.ceil(fullLen / (n + 1));
len = fullLen / n2;
$.writeln(i + ': fullLen = ' + fullLen + '\tlen = ' + len + '\tn2 = ' + n2);
} else {
len = getT4Len(q, 0) / n;
n2 = n;
}
if (len <= 0) continue;
redrawflg = true;
for (k = 1; k < n2; k++) {
ar.push(getT4Len(q, len * k));
}
pnts.push(ar);
}
if (redrawflg) addPnts(paths[h], pnts, false);
}
activeDocument.selection = paths;
}
// ----------------------------------------------
// addPnts: adds anchors to pathitem "pi"
// an example of usage:
/* var pi=activeDocument.selection[0];
var pnts = [ [0, 0.3,0.8,0.5],
[3, 0.5] ]; // [ [i, t,t,t,t...],[i, t,t..
addPnts(pi,pnts,true);
*/
function addPnts(pi, pnts, need2sort) { // target pathItem, list, need to sort the parameters
// pnts = [ [index, t,t,t,t...],[index, t,t..
// items must be ordered by index
// an item without t ([index]) is acceptable. an empty allay is not acceptable.
// an index out of bounds is acceptable. the range of t is 0 < t < 1.
var p = pi.pathPoints;
var pnts2 = [];
var adjNextLDir = 0;
var adjFirstLDir = 0;
var idx = (pi.closed && pnts[pnts.length - 1][0] == p.length - 1) ? 0 : pnts[0][0];
var ar = pnts.shift();
var nidx = ar.shift();
var j, pnt, q;
for (var i = idx; i < p.length; i++) {
pnts2.push(getDat(p[i]));
if (adjNextLDir > 0) {
pnts2[pnts2.length - 1][2] = adjHanP(p[i], 0, 1 - adjNextLDir);
}
if (nidx == i) {
if (ar.length > 0) {
if (need2sort) {
ar.sort();
ar = getUniq(ar);
}
if (i == p.length - 1 && idx == 0) {
adjFirstLDir = ar[ar.length - 1];
}
pnts2[pnts2.length - 1][1] = adjHanP(p[i], 1, ar[0]),
ar.unshift(0);
ar.push(1);
nxi = parseIdx(p, i + 1);
if (nxi < 0) break;
q = [p[i].anchor, p[i].rightDirection,
p[nxi].leftDirection, p[nxi].anchor];
if (arrEq(q[0], q[1]) && arrEq(q[2], q[3])) {
for (j = 1; j < ar.length - 1; j++) {
pnt = bezier(q, ar[j]);
pnts2.push([pnt, pnt, pnt, PointType.CORNER]);
}
} else {
for (j = 1; j < ar.length - 1; j++) {
pnts2.push(getDivPnt(q, ar[j - 1], ar[j], ar[j + 1]));
}
}
adjNextLDir = ar[ar.length - 2];
} else {
adjNextLDir = 0;
}
if (pnts.length > 0) {
ar = pnts.shift();
nidx = ar.shift();
}
} else {
adjNextLDir = 0;
}
}
if (adjFirstLDir > 0) pnts2[0][2] = adjHanP(p[0], 0, 1 - adjFirstLDir);
if (pnts2.length > 0) applyData2AfterIdx(p, pnts2, idx - 1);
}
// ----------------------------------------------
function getUniq(ar) { // Array (sorted)
if (ar.length < 2) return ar;
var ar2 = [ar[0]];
var torelance = 0.01;
for (var i = 1; i < ar.length; i++) {
if (ar[i] - ar2[ar2.length - 1] > torelance) ar2[ar2.length] = ar[i];
}
return ar2;
}
// ----------------------------------------------
// returns an array for properties of a pathpoint
function getDat(p) { // pathPoint
with (p) return [anchor, rightDirection, leftDirection, pointType];
}
// ----------------------------------------------
// magnifies a handle by m
function adjHanP(p, n, m) { // p=pathpoint, n=0:leftDir, n=1:rightDir, m=magnification rate
with (p) {
var d = (n == 1 ? rightDirection : leftDirection);
return [anchor[0] + (d[0] - anchor[0]) * m,
anchor[1] + (d[1] - anchor[1]) * m];
}
}
// ----------------------------------------------
// returns an array for properties of a pathpoint
// that corresponds to the parameter "t1"
// q=4 points, t0-2=parameters, anc=coordinate of anchor
function getDivPnt(q, t0, t1, t2, anc) {
if (!anc) anc = bezier(q, t1);
var r = defDir(q, 1, t1, anc, (t2 - t1) / (1 - t1));
var l = defDir(q, 0, t1, anc, (t1 - t0) / t1);
if (straightLinesOnlyMode) {
return [anc, anc, anc, PointType.SMOOTH];
} else {
return [anc, r, l, PointType.SMOOTH];
}
}
// ----------------------------------------------
// returns the [x, y] coordinate of the handle of the point on the bezier curve
// that corresponds to the parameter "t"
// q=4 points, t=paramter, anc=coordinate of anchor, m=magnification ratio
function defDir(q, n, t, anc, m) { // n=0:ldir, n=1:rdir
var dir = [t * (t * (q[n][0] - 2 * q[n + 1][0] + q[n + 2][0]) + 2 * (q[n + 1][0] - q[n][0])) + q[n][0],
t * (t * (q[n][1] - 2 * q[n + 1][1] + q[n + 2][1]) + 2 * (q[n + 1][1] - q[n][1])) + q[n][1]];
return [anc[0] + (dir[0] - anc[0]) * m,
anc[1] + (dir[1] - anc[1]) * m];
}
// ----------------------------------------------
// return the [x, y] coordinate on the bezier curve
// that corresponds to the paramter "t"
function bezier(q, t) {
var u = 1 - t;
return [u * u * u * q[0][0] + 3 * u * t * (u * q[1][0] + t * q[2][0]) + t * t * t * q[3][0],
u * u * u * q[0][1] + 3 * u * t * (u * q[1][1] + t * q[2][1]) + t * t * t * q[3][1]];
}
// ----------------------------------------------
function applyData2Path(p, pnts) { // pathpoint, list
// (format:[[ anchor, rightDirection, leftDirection, poinType ],...]
if (pnts.length < 1) return;
var pt;
while (p.length > pnts.length) {
p[p.length - 1].remove();
}
for (var i in pnts) {
pt = i < p.length ? p[i] : p.add();
with (pt) {
anchor = pnts[i][0];
rightDirection = pnts[i][1];
leftDirection = pnts[i][2];
pointType = pnts[i][3];
}
}
}
// ----------------------------------------------
function applyData2AfterIdx(p, pnts, idx) { // pathpoint, list, index
if (idx == null || idx < 0) {
applyData2Path(p, pnts);
return;
}
var pt;
while (p.length - 1 > idx) {
p[p.length - 1].remove();
}
for (var i = 0; i < pnts.length; i++) {
pt = p.add();
with (pt) {
anchor = pnts[i][0];
rightDirection = pnts[i][1];
leftDirection = pnts[i][2];
pointType = pnts[i][3];
}
}
}
// ------------------------------------------------
// returns true, if a segment between pathpoints ps1 and ps2 is selected
function sideSelection(ps1, ps2) {
return (ps1.selected != PathPointSelection.NOSELECTION
&& ps1.selected != PathPointSelection.LEFTDIRECTION
&& ps2.selected != PathPointSelection.NOSELECTION
&& ps2.selected != PathPointSelection.RIGHTDIRECTION);
}
// ------------------------------------------------
// if the contents of both arrays are equal, return true (lengthes must be same)
function arrEq(arr1, arr2) {
for (var i in arr1) {
if (arr1[i] != arr2[i]) {
return false;
}
}
return true;
}
// ------------------------------------------------
// return the bezier curve parameter "t"
// at the point which the length of the bezier curve segment
// (from the point start drawing) is "len"
// when "len" is 0, return the length of whole this segment.
function getT4Len(q, len) {
var m = [q[3][0] - q[0][0] + 3 * (q[1][0] - q[2][0]),
q[0][0] - 2 * q[1][0] + q[2][0],
q[1][0] - q[0][0]];
var n = [q[3][1] - q[0][1] + 3 * (q[1][1] - q[2][1]),
q[0][1] - 2 * q[1][1] + q[2][1],
q[1][1] - q[0][1]];
var k = [m[0] * m[0] + n[0] * n[0],
4 * (m[0] * m[1] + n[0] * n[1]),
2 * ((m[0] * m[2] + n[0] * n[2]) + 2 * (m[1] * m[1] + n[1] * n[1])),
4 * (m[1] * m[2] + n[1] * n[2]),
m[2] * m[2] + n[2] * n[2]];
var fullLen = getLength(k, 1);
if (len == 0) {
return fullLen;
} else if (len < 0) {
len += fullLen;
if (len < 0) return 0;
} else if (len > fullLen) {
return 1;
}
var t, d;
var t0 = 0;
var t1 = 1;
var torelance = 0.001;
for (var h = 1; h < 30; h++) {
t = t0 + (t1 - t0) / 2;
d = len - getLength(k, t);
if (Math.abs(d) < torelance) break;
else if (d < 0) t1 = t;
else t0 = t;
}
return t;
}
// ------------------------------------------------
// return the length of bezier curve segment
// in range of parameter from 0 to "t"
// "m" and "n" are coefficients.
function getLength(k, t) {
var h = t / 128;
var hh = h * 2;
var fc = function (t, k) {
return Math.sqrt(t * (t * (t * (t * k[0] + k[1]) + k[2]) + k[3]) + k[4]) || 0
};
var total = (fc(0, k) - fc(t, k)) / 2;
for (var i = h; i < t; i += hh) {
total += 2 * fc(i, k) + fc(i + h, k);
}
return total * hh;
}
// ------------------------------------------------
// extract PathItems from the selection which length of PathPoints
// is greater than "n"
function getPathItemsInSelection(n, paths) {
if (documents.length < 1) return;
var s = activeDocument.selection;
if (!(s instanceof Array) || s.length < 1) return;
extractPaths(s, n, paths);
}
// --------------------------------------
// extract PathItems from "s" (Array of PageItems -- ex. selection),
// and put them into an Array "paths". If "pp_length_limit" is specified,
// this function extracts PathItems which PathPoints length is greater
// than this number.
function extractPaths(s, pp_length_limit, paths) {
for (var i = 0; i < s.length; i++) {
if (s[i].locked || s[i].hidden) {
continue;
} else if (s[i].typename == "PathItem") {
if (pp_length_limit
&& s[i].pathPoints.length <= pp_length_limit) {
continue;
}
paths.push(s[i]);
} else if (s[i].typename == "GroupItem") {
// search for PathItems in GroupItem, recursively
extractPaths(s[i].pageItems, pp_length_limit, paths);
} else if (s[i].typename == "CompoundPathItem") {
// searches for pathitems in CompoundPathItem, recursively
// ( ### Grouped PathItems in CompoundPathItem are ignored ### )
extractPaths(s[i].pathItems, pp_length_limit, paths);
}
}
}
// ----------------------------------------------
// return pathpoint's index. when the argument is out of bounds,
// fixes it if the path is closed (ex. next of last index is 0),
// or return -1 if the path is not closed.
function parseIdx(p, n) { // PathPoints, number for index
var len = p.length;
if (p.parent.closed) {
return n >= 0 ? n % len : len - Math.abs(n % len);
} else {
return (n < 0 || n > len - 1) ? -1 : n;
}
} The settings are these: var absoluteDistanceMode = true; // divides a path segment to keep approximately n pts distance between added points var straightLinesOnlyMode = true; // convert curves to straight lines var divisionsOrApproximateDistanceBetweenPoints = 10; // in absoluteDistanceMode it is the (approximate) distance between points, measured in pts, otherwise it is the number of divisions @HiroyukiSato Thanks for writing such terrific scripts! 🙂 Hope I haven't made too much of a mess of the above modification. - Mark
... View more
‎Jan 10, 2021
01:49 PM
Interesting problem. My first thought is to cause the script to approximate the curves with small straight line segments, by using say, Zig Zag or Scribble or something like that, with settings that add anchor points but don't actually deform the path. Another idea is to modify Hiroyuki Sato's script Divide to calculate the points for you. Then you'd be able to run your algorithm. I'm interested to know how you go, so please post back if you get anywhere with it. Also wondered if you'd like to post the algorithm you ported from Java? - Mark
... View more
‎Jan 10, 2021
01:42 PM
Yes it seems to be normal object and selected. Just drew a rectangle and ran the code with it selected. Edit: removed call for help, as my issue was solved by Carlos. 🙂 - Mark
... View more
‎Jan 09, 2021
10:48 PM
I can't reproduce that problem. Any chance you could you post screenshot of layers palette, or link to sample file?
... View more
‎Jan 09, 2021
06:52 PM
Interesting! I am on a Mac, so could be that, but maybe my code is wrong. Here's what I'm using: // apply offset path live effect to selected path
var path = app.activeDocument.selection[0];
xmlstring = '<LiveEffect name="Adobe Offset Path"><Dict data="R mlim 4 R ofst 20 I jntp 2 "/></LiveEffect>';
path.applyEffect(xmlstring); I get this: Runtime Error: Error Code# 24: path.applyEffect is not a function.
... View more
‎Jan 09, 2021
06:48 PM
2 Upvotes
4th attempt! Now handles GroupItems. Feel free to ignore attempt 3, I've left it just for learning purposes. There are two ways you may want to handle groups: 1) calculate area for each individual item inside the group, or 2) calculate the aggregate area of all the grouped items. If you want option 2) just comment out the itemsInsideGroupItems line. Just for fun I also changed the way the parameters work for specifying the target area value and unit. I put them in a string. Example values are: '4 square inches', '4in','4 sq inch' will give same result. Other examples are:'100mm', '800 pt'. If the parameter is a number, not a string, it will be interpreted as points. // start with the selected items
var items = app.activeDocument.selection;
// comment out the following line if you want each groups' area to be calculated, rather than the items inside each group individually
items = itemsInsideGroupItems(items);
// this is where you specify your target size ()
scaleItemsToArea(items, '4 square inches');
function scaleItemsToArea(items, targetString) {
// very simple parsing of targetString
targetString = String (targetString);
var targetAreaInSquareUnits = Number(targetString.match(/\d+/)[0]);
var unitType;
// note: only looks for 'in' or 'mm'
if (targetString.search(/(in|\")/) > -1) {
unitType = 'in';
} else if (targetString.search(/mm/) > -1) {
unitType = 'mm';
} else {
unitType = 'pt'
}
// scale each item
for (var i = 0; i < items.length; i++) {
scaleToArea(items[i], targetAreaInSquareUnits, unitType);
}
}
function scaleToArea(item, targetAreaInSquareUnits, unitType) {
var itemAreaInSquareUnits = areaOfItem(item, unitType);
var scaleFactor = (Math.sqrt(targetAreaInSquareUnits / itemAreaInSquareUnits)) * 100;
if (scaleFactor != NaN) {
item.resize(scaleFactor, scaleFactor);
}
}
function areaOfItem(item, unitType) {
var itemAreaInSquareUnits;
var itemAreaInSquarePoints = areaOfItemInSquarePoints(item);
if (unitType == 'in') {
var ptsIn1inch = 72;
itemAreaInSquareUnits = itemAreaInSquarePoints / (ptsIn1inch * ptsIn1inch);
} else if (unitType == 'mm') {
var ptsIn1mm = 2.834645669;
itemAreaInSquareUnits = itemAreaInSquarePoints / (ptsIn1mm * ptsIn1mm);
} else {
// no unitType specified, use points
itemAreaInSquareUnits = itemAreaInSquarePoints;
}
return itemAreaInSquareUnits;
}
function areaOfItemInSquarePoints(item) {
var area = 0;
if (item.typename == 'PathItem') {
area = item.area;
} else if (item.typename == 'CompoundPathItem') {
for (var j = 0; j < item.pathItems.length; j++) {
area += item.pathItems[j].area;
// $.writeln('item.pathItems[j].area = ' + item.pathItems[j].area + ' area = ' + area);
}
} else if (item.typename == 'GroupItem') {
for (var j = 0; j < item.pageItems.length; j++) {
area += areaOfItemInSquarePoints(item.pageItems[j]);
// $.writeln('item.pathItems[j].area = ' + item.pathItems[j].area + ' area = ' + area);
}
} else {
// for other types of items, resort to width x height
area = item.width * item.height;
}
return Math.abs(Math.round(area * 10000) / 10000);
}
function itemsInsideGroupItems(items) {
// returns an array containing items, including items found inside GroupItems
try {
var found = [];
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (item.typename == 'GroupItem') {
found = found.concat(itemsInsideGroupItems(item.pageItems));
} else {
found.push(item);
}
}
return found;
} catch (e) {
return found;
}
} As usual, not much testing done, so please let me know if it works as you'd expect. - Mark
... View more
‎Jan 09, 2021
04:43 PM
And 3rd attempt, this one better organised I think: scaleSelectedItemsToMatchTargetArea(4, 'inch');
function scaleSelectedItemsToMatchTargetArea(targetAreaInSquareUnits, unitType) {
var items = app.activeDocument.selection;
for (var i = 0; i < items.length; i++) {
scaleToArea(items[i], targetAreaInSquareUnits, unitType);
}
}
function scaleToArea(item, targetAreaInSquareUnits, unitType) {
var itemAreaInSquareUnits = areaOfItem(item, unitType);
var scaleFactor = (Math.sqrt(targetAreaInSquareUnits / itemAreaInSquareUnits)) * 100;
if (scaleFactor != NaN) {
item.resize(scaleFactor, scaleFactor);
}
}
function areaOfItem(item, unitType) {
var itemAreaInSquareUnits;
var itemAreaInSquarePoints = areaOfItemInSquarePoints(item);
if (unitType == 'in' || unitType == 'inch') {
var ptsIn1inch = 72;
itemAreaInSquareUnits = itemAreaInSquarePoints / (ptsIn1inch * ptsIn1inch);
} else if (unitType == 'mm' || unitType == 'millimetres') {
var ptsIn1mm = 2.834645669;
itemAreaInSquareUnits = itemAreaInSquarePoints / (ptsIn1mm * ptsIn1mm);
} else {
// no unitType specified, use points
itemAreaInSquareUnits = itemAreaInSquarePoints;
}
return itemAreaInSquareUnits;
}
function areaOfItemInSquarePoints(item) {
var area = 0;
if (item.typename == 'PathItem') {
area = item.area;
} else if (item.typename == 'CompoundPathItem') {
for (var j = 0; j < item.pathItems.length; j++) {
area += item.pathItems[j].area;
}
} else {
// for other types of items, resort to width x height
area = item.width * item.height;
}
return Math.abs(Math.round(area * 10000) / 10000);
} Still largely untested, but let me know how it goes! - Mark Edit: took out my $.writelns!
... View more
‎Jan 09, 2021
02:20 PM
2nd attempt! 🙂 var items = app.activeDocument.selection;
var targetAreaInSquareInches = 4;
for (var i = 0; i < items.length; i++) {
var item = items[i];
var areaInSquarePoints = areaOfItemInSquarePoints(item);
var areaInSquareInches = areaInSquarePoints / (72 * 72);
var scaleFactor = (Math.sqrt(targetAreaInSquareInches / areaInSquareInches)) * 100;
if (scaleFactor == NaN) continue;
item.resize(scaleFactor, scaleFactor);
}
function areaOfItemInSquarePoints(item) {
var area = 0;
if (item.typename == 'PathItem') {
area = item.area;
} else if (item.typename == 'CompoundPathItem') {
for (var j = 0; j < item.pathItems.length; j++) {
area += item.pathItems[j].area;
}
} else {
// for other types of items, resort to width x height
area = item.width * item.height;
}
return Math.abs(Math.round(area * 10000) / 10000);
} - Mark
... View more
‎Jan 09, 2021
01:58 PM
You are right! I'll fix it.
... View more
‎Jan 07, 2021
08:30 PM
1 Upvote
Here's my take: incrementNumberInTextFrame(selection[0]);
function incrementNumberInTextFrame(item) {
if (item != undefined && item.typename == "TextFrame") {
var copyOfItem = item.duplicate();
copyOfItem.translate(0, -item.height);
var regex = /\d+/;
var numberString = item.contents.match(regex)[0];
copyOfItem.contents = copyOfItem.contents.replace(regex, Number(numberString) + 1);
selection = [copyOfItem];
redraw();
}
} This will increment the first instance of any number in the textframe given to the function. It shouldn't matter what other characters are in the text frame. - Mark Edit: adjusted code for better meaningful variable names.
... View more
‎Jan 07, 2021
02:47 PM
Hi Silly-V, I was very interested to read the thread you linked, but when I try it (in CC2021) it appears that the applyEffect(xml) method is missing! Is this just me? - Mark
... View more
‎Jan 07, 2021
01:57 PM
Hi Luthyn, I've had this issue many times, and it is usually (in my case) caused by poor gridfitting—the way pixels line up with the vector points. The solution I use is to: Set the document units to pixels Set the position and size of the artboard to whole units of pixels Adjust artwork so that it aligns to the pixel grid It helps to turn on Pixel Preview (View menu) and use the Transform Palette to check the position of objects and points. Using the Control Palette's "Align to pixel grid" option can sometimes help, but sometimes hinder, this process (probably due to my inexperience). - Mark
... View more
‎Jan 05, 2021
10:53 PM
1 Upvote
Hi kylwell, here's a rough first go. If the item has an area property (PathItems do have this) the script will use it, otherwise will use width and height to calculate the area, which is crude to say the least. There's certainly room for more sophistication here. var items = app.activeDocument.selection;
var targetAreaInSquareInches = 4;
for (var i = 0; i < items.length; i++) {
var item = items[i];
var areaInSquarePoints = item.area != undefined ? item.area : item.width * item.height;
var areaInSquareInches = areaInSquarePoints / (72 * 72);
var scaleFactor = (Math.sqrt(targetAreaInSquareInches / areaInSquareInches)) * 100;
item.resize(scaleFactor, scaleFactor);
} - Mark
... View more
‎Jan 05, 2021
10:17 PM
If it's not a plugin, I'm very interested! I'd love to be able to have access to mouse events outside of ScriptUI. Not sure if it's possible at the moment.
... View more
‎Jan 05, 2021
10:15 PM
1 Upvote
So good! 🙂 Nice use of diverse tools to solve a problem. OP might find a similar product on their platform if not Mac?
... View more
‎Jan 05, 2021
10:09 PM
I know! It's awesome and I love it too. So helpful. Thanks again.
... View more
‎Jan 04, 2021
10:21 PM
Hi kenta0D4D, it looks like the video shows a plug-in, not a plain script. If a plain script solution won't work for your case, you might need to find a developer who can make plug-ins. Sorry, I can't help. It's out of my league! - Mark
... View more
‎Jan 04, 2021
10:16 PM
3 Upvotes
Hi Ray, Hope it's ok, just for learning myself, I've made a couple of versions of your script to show different uses of regular expressions. Version 2 uses match and version 3 uses replace methods of String. Using the RegExp exec method has advantages better seen when used in a loop I think. function makeLabel2() {
var anItem = selection[0];
var label;
if (anItem != undefined && anItem.typename == "TextFrame") {
label = anItem.duplicate();
label.translate(0, -selection[0].height);
// match returns the found strings, in an array
var prefix = anItem.contents.match(/^[A-Z]/)[0];
var index = anItem.contents.match(/\d+/)[0];
var suffix = anItem.contents.match(/[a-z]/)[0];
label.contents = nextChar(prefix) + (Number(index)+1) + nextChar(suffix);
selection = [label];
redraw();
}
function nextChar(c) {
return String.fromCharCode(c.charCodeAt(0) + 1);
}
}
function makeLabel3() {
var anItem = selection[0];
if (anItem != undefined && anItem.typename == "TextFrame") {
var label = anItem.duplicate();
label.translate(0, -anItem.height);
// regex replace method can take a function as 2nd parameter!
label.contents = anItem.contents.replace(/^([A-Z])(\d+)([a-z])/, function (all, prefix, index, suffix) {
return nextChar(prefix) + (Number(index) + 1) + nextChar(suffix);
})
selection = [label];
redraw();
}
function nextChar(c) {
return String.fromCharCode(c.charCodeAt(0) + 1);
}
} Thanks for the post. It got me thinking! - Mark
... View more
‎Dec 25, 2020
07:09 PM
No quite sure yet what you mean. You want script to select a linked image (PlacedItem) that has a scale greater than 100?
... View more
‎Dec 24, 2020
02:25 PM
3 Upvotes
Hi, here's an example of getting scale and rotation of linked (or embedded) item: var item = app.activeDocument.selection[0];
if (item.typename == 'PlacedItem' || item.typename == 'RasterItem') {
var m = item.matrix;
var rotatedAmount = asDegrees(Math.atan2(m.mValueB, m.mValueA));
//rotation goes the other way for placed items!
if (item.typename == 'PlacedItem') rotatedAmount = -rotatedAmount;
var scaledAmount = [m.mValueA * 100, m.mValueD * 100];
alert(item.typename
+ '\nscaleX = ' + scaledAmount[0]
+ '\nscaleY = ' + scaledAmount[1]
+ '\nrotation = ' + rotatedAmount
);
}
function asDegrees(radians) { return radians * 57.2957795 }
... View more
‎Nov 19, 2020
01:21 PM
Just checking: you are also considering the path from the XMP manifest entry? (Sorry I don't have time to test right now, but I assume you have.)
... View more
‎Nov 18, 2020
01:25 PM
I'm don't have a perfect answer. Could you try this: Check if item has a file property (ie. item.file doesn't throw an error) and get the file suffix from the file name. var item = app.activeDocument.pageItems[0];
var suffix = getItemFileSuffix(item);
if (suffix != undefined) {
// now you know the file format is not N/A
if (suffix == 'jpg') {
//do something?
}
}
function getItemFileSuffix(item) {
var suffix;
if (item.typename == 'PlacedItem' || item.typename == 'RasterItem') {
try {
suffix = examplePageItem.file.fullName.split('.').pop();
} catch (error) { }
}
return suffix;
}
... View more
‎Nov 11, 2020
12:19 PM
1 Upvote
Hi! Take a look at this post. It discusses the issue on a specific file. The answer mentions this tool which may be useful in your case. Top ideas I can think of are: simplify geometry where possible (eg. using compound path for mask, rather than two separate masks) using symbols where possible (where you have identical elements repeated) exporting the svg with a lower precision (number of decimals). Also, if you're willing to go further, open the svg file in a text editor after exporting, and you can analyse it and compare it to different versions to see how they are smaller, based on character count. - Mark
... View more
‎Nov 10, 2020
12:55 PM
Yes, very well explained, and taught me something. Thanks! Again, excellent work. 🙂
... View more
‎Nov 10, 2020
12:35 AM
Excellent work! One question though... why don't you just get PlacedItems from the start? eg. var artItems = app.activeDocument.placedItems; Then you won't have to worry. Mark
... View more
‎Nov 10, 2020
12:20 AM
Oh, that's good to know.
... View more
‎Nov 07, 2020
11:44 PM
Hi femkeblanco, I would call the variable 'name' in the case you mention. I think its actually perfect. Why is it bad? - Mark
... View more