m1b
Community Expert
m1b
Community Expert
Activity
‎Mar 11, 2025
04:45 AM
@gaurav_2111, further to what @Willi Adelberger mentioned, of using pre-defined styles for everything, the more of your datasheet you can keep in the same "story" (a single text-flow, no matter how many text frames are linked or how many anchored objects), the easier it will be to edit for the translations without messing up your desired layout.
Also, once you have set up the styles, and received the translated version back, perhaps you could create a full set of styles (or as needed) for the translated text, so that next time you can explain to the translators that they must use those styles.
Feel free to post an example page or two, both your document and the translated document, and we can advise you of a good way to set it up.
- Mark
... View more
‎Mar 10, 2025
04:30 PM
Thanks @psar12345 I have updated the script above so that it handles empty clipping groups.
- Mark
... View more
‎Mar 10, 2025
03:48 PM
1 Upvote
I've simplified your example to this:
(function () {
var test = function () {
var aplScript = "display dialog item 1 of arguments";
return app.doScript(aplScript, ScriptLanguage.APPLESCRIPT_LANGUAGE, ['Hello']);
}
alert(test());
}());
This throws the error on my machine ID 20.2. Feel free to test on 20.1 if you get the chance.
- Mark
... View more
‎Mar 10, 2025
03:39 PM
Thanks @Madhawk65 that is interesting.
Actually I've always found the arguments parameter of app.doScript a bit flaky and I never use it—I just wrap it all up in a function like you did. From memory I thought the arguments parameter for doScript required an Array though but your code gives a String, so I might not be right there.
If you had time and inclination, you could pare that example down to remove any unnecessary parts—or have you already done so? For example does the problem only occur with "do shell script" AppleScript or with any Applescript if called with a certain nesting/scope structure? I think only then would we have a chance to write a bug report.
Otherwise I would follow your approach of just avoiding the "arguments" parameter of app.doScript altogether.
- Mark
... View more
‎Mar 10, 2025
04:40 AM
Hi @Madhawk65, did you solve this one? I just wanted to confirm that the problem isn't general for Applescripts run via app.doScript. I can run old script's that call Applescript and they still work normally.
Robert asked you, but you didn't answer I wasn't sure you were answering this specific question: Can you run the Applescript code—the exact Applescript generated by your script—from Script Editor? That would be the place to do the debugging first.
- Mark
... View more
‎Mar 10, 2025
03:56 AM
Hi @psar12345 I would love to fix that error. Can you post an Illustrator file (saved as pdf) with the object that causes the error?
- Mark
... View more
‎Mar 09, 2025
04:36 AM
@dublove I'm glad to hear that the reinstall to the default location fixed the BridgeTalk problem. I don't know why app.bringToFront() didn't work—it works for me on MacOS. But well done on finding the BridgeTalk.bringToFront(targetApp) method! Maybe that is the best way for cross platform use.
- Mark
... View more
‎Mar 08, 2025
04:06 AM
@dublove you have a few possible options I think:
1. get BridgeTalk working (best option), or
2. maybe you can use a Visual Basic call from ExtendScript? I use MacOS so I can't help much, but maybe something like this (it's ChatGPT output so might be wrong!):
var vbscript = 'Set app = CreateObject("Photoshop.Application")\n' +
'app.Open "C:\\path\\to\\your\\image.jpg"';
app.doScript(vbscript, ScriptLanguage.VISUAL_BASIC);
3. something similar to (2) eg. write a powershell script to disk and .execute() it.
If you try (2) and it works for opening one image, we can adjust the code to add all the paths together.
- Mark
... View more
‎Mar 08, 2025
01:56 AM
1 Upvote
HI @Eugene Tyson, Dirk will be the expert here. I don't know anything about the SDK.
- Mark
... View more
‎Mar 08, 2025
01:32 AM
1 Upvote
@Dave Creamer of IDEAS and @Mike Witherell your side discussion has brought back memories for me, too! My first Mac was a "Fat Mac" (I think 512K). I don't think I got a 20MB HD until I had upgraded to the first Mac SE. I can still remember Illustrator 1.0 running on it. Prior to that I was using MacPaint and then, I think, "Super Paint" (300dpi!). Put everything together in PageMaker.
- Mark
... View more
‎Mar 08, 2025
01:26 AM
@dublove
> it should be possible to evoke any program with a path
Sure, you should be able to do directly in ExtendScript. This works on my machine, but you will need to put the path to your photoshop.
// use your own path to Photoshop here:
var photoshopAppFile = File('/Applications/Adobe Photoshop 2025/Adobe Photoshop 2025.app');
// launch it
photoshopAppFile.execute();
This won't fix the BridgeTalk issue though.
- Mark
... View more
‎Mar 08, 2025
12:46 AM
1 Upvote
Okay, that's probably how it's become muddled. I know you can specify the app location for CC but I don't think you can have some apps here and other apps there—they seem to need to be in the same folder. But unfortunately I don't know anything about that. Maybe re-installing Photoshop completely is the best fix? But it might have to be in the same folder as the rest of the CC apps for BridgeTalk to see it by default. Also back up your settings, eg. key shortcuts etc.
- Mark
... View more
‎Mar 07, 2025
10:35 PM
1 Upvote
@dublove so the sticking point is that BridgeTalk cannot get a specifier for Photoshop:
(function () {
var photoshop = BridgeTalk.getSpecifier("photoshop");
if (!photoshop)
alert("Photoshop is not available.");
else
alert('Specifier = ' + photoshop);
})();
If this doesn't work, then something is wrong with your installation, which is beyond my limited knowledge.
- Mark
... View more
‎Mar 07, 2025
08:15 PM
Hi @dublove, did you test my updated script? I refactored something at the last minute and stupidly forgot to finish it. If still no response, can you insert this line as the first line of `openPaths` function:
alert(paths+delimiter);
It would be good to know if even that part works.
- Mark
... View more
‎Mar 07, 2025
07:19 PM
1 Upvote
@Eugene Tyson this is an example of how I like to handle BridgeTalk calls. I write a function that I then convert to string using `Function.toSource()` then I call it inside an IIFE, adding parameters to the IIFE call (these must be strings too). (Edit: note that I don't actually invoke `toSource`—the function `openPaths` is impicitly coerced to a string by the `replace` method I used to construct the bt.body string.) This might seem a bit opaque at first but for me it avoids a lot of the messy string concatenation dance that goes on. It also means that I can literally test the Photoshop function `openPaths` directly in photoshop to make sure it works!
@dublove this is my attempt at a script to "Open Selected Images in Photoshop". It works for me on MacOS. Does it work for you on Windows?
- Mark
/**
* @file Open Selected Links In Photoshop.js
*
* Opens the selected linked file(s) in Photoshop.
*
* @author m1b
* @version 2025-03-08
* @discussion https://community.adobe.com/t5/indesign-discussions/how-to-open-images-with-different-default-applications-in-indesign-and-resource-manager-windows/m-p/15197180
*/
(function () {
if (0 === app.documents.length)
return alert('Please open a document and try again.');
var doc = app.activeDocument,
items = doc.selection;
if (0 === items.length)
return alert('Please select a linked graphic frame and try again.');
// collect paths for each selected item
var paths = [];
for (var i = 0; i < items.length; i++) {
var item = items[i];
// maybe user selected the image, not the frame
if ('Image' === item.constructor.name)
item = item.parent;
if (
!item.hasOwnProperty('graphics')
|| 0 === item.graphics.length
|| !item.graphics[0].itemLink
|| LinkStatus.NORMAL !== item.graphics[0].itemLink.status
)
// ignore anything we can't use
continue;
// first linked image is all we need right now
paths.push(item.graphics[0].itemLink.filePath);
}
if (0 === paths.length)
return alert('Please select a linked graphic frame and try again.');
// open the paths in photoshop
openPathsInPhotoshop(paths);
})();
/**
* Opens the given `paths` in Photoshop.
* @author m1b
* @version 2025-03-08
* @param {Array<String>} paths - the paths to open.
*/
function openPathsInPhotoshop(paths) {
const DELIMITER = '###';
var photoshop = BridgeTalk.getSpecifier("photoshop");
if (!photoshop)
return alert("Photoshop is not available.");
// send script via BridgeTalk
var bt = new BridgeTalk();
bt.target = photoshop;
// arrange the function inside an IIFE string,
// and perform string replacements to insert
// our variables
bt.body = '(#FN#)("#P#","#D#");'
.replace('#D#', DELIMITER)
.replace('#P#', paths.join(DELIMITER))
.replace('#FN#', openPaths);
bt.onResult = undefined;
bt.send(1000);
};
/**
* Photoshop function to open the given `paths`.
* Note: cannot use // style comments here because
* of the way I stringify it.
* @param {String} paths - the paths, delimited.
* @param {String} delimiter - the string used to delimit `paths`.
*/
function openPaths(paths, delimiter) {
app.bringToFront();
/* make aray by splitting paths */
paths = paths.split(delimiter);
for (var i = 0; i < paths.length; i++)
if (File(paths[i]).exists)
app.open(File(paths[i]));
};
Edit 2025-03-08: fixed a bug, where I forgot to include the string delimiter. Oops!
... View more
‎Mar 07, 2025
06:41 PM
Hi @dublove and @Eugene Tyson, at a quick glance, the first problem I noticed is this line:
app.doScript('var wsh = new ActiveXObject("WScript.Shell"); wsh.Run(' + JSON.stringify(cmd) + ', 1, false);', ScriptLanguage.JAVASCRIPT);
The problem is that the JSON object is not available at runtime. You would need to //@include it. However there is no reason to stringify `cmd` which is already a String. So try just changing to
app.doScript('var wsh = new ActiveXObject("WScript.Shell"); wsh.Run(' + cmd + ')', ScriptLanguage.JAVASCRIPT);
See if that helps, but there seems to be other issues which I'll have a look at later if you still need help.
If you are using ExtendScript debugger with VSCode—you can use this line:
debugger;
at a point in your code where you want to check the contents of a variable. Then you run the code (from VSCode, not directly from Indesign). The debugger should pause at the "debugger" command and in the Debug Console in VSCode (your other best friend) you can type commands and receive outputs.
So just before your app.doScript, you could put "debugger;" and then when debugger paused at that breakpoint, in the Debug Console you could type "cmd" (and press return) and it will print out the contents of the "cmd" variable. And then you could copy/paste the command into a new script and test just that command in Photoshop or wherever and see what errors it's getting, and then go back and fix it in your main script.
- Mark
... View more
‎Mar 06, 2025
04:16 PM
1 Upvote
Hi @psar12345, calculating the exact bounds of a page item is surprisingly involved. I wrote a function that makes a valiant attempt at doing it. You can see it working in the following demo script. The function `getItemBoundsIllustrator` returns [L, T, R, B]. Give it a try if you like.
- Mark
/**
* @file Get Item Bounds.js
*
* Demonstration of calculating the bounds
* of the selected item(s) and draws a
* box to show the bounds.
*
* @author m1b
* @version 2025-03-07
*/
(function () {
// enum to make the function call below more readable
var BoundsType = {
GEOMETRIC_BOUNDS: true,
VISIBLE_BOUNDS: false,
};
var doc = app.activeDocument;
if (0 === doc.selection.length)
return alert('Please select and item and try again.');
// calculate the bounds of the selection
var bounds = getItemBoundsIllustrator(doc.selection, BoundsType.VISIBLE_BOUNDS);
if (bounds)
// for demonstration purposes, draw a box to show bounds
var box = drawRectangle(doc, bounds, { opacity: 30, fillColor: makeColor([255, 50, 150]) });
})();
/**
* Draws a rectangle to the document.
* @param {Document|Layer|GroupItem} container - an Illustrator container.
* @param {Array<Number>} bounds - [T, L, B, R].
* @param {Object} props - properties to assign to the rectangle.
* @return {PathItem} - the rectangle.
*/
function drawRectangle(container, bounds, properties) {
properties = properties || {};
var rectangle = container.pathItems.rectangle(bounds[1], bounds[0], bounds[2] - bounds[0], -(bounds[3] - bounds[1])); // TLWH
// defaults
rectangle.filled = true;
rectangle.stroked = false;
// apply properties
for (var key in properties)
if (properties.hasOwnProperty(key))
rectangle[key] = properties[key];
return rectangle;
};
/**
* Return an RGB color.
* @param {Array<Number>} breakdown - the color breakdown.
* @returns {RGBColor}
*/
function makeColor(breakdown) {
var colr = new RGBColor();
colr.red = breakdown[0];
colr.green = breakdown[1];
colr.blue = breakdown[2];
return colr;
};
/**
* Returns bounds of item(s).
* @author m1b
* @version 2025-03-11
* @param {PageItem|Array<PageItem>} item - an Illustrator PageItem or array of PageItems.
* @param {Boolean} [geometric] - if false, returns visible bounds.
* @param {Array} [bounds] - private parameter, used when recursing.
* @returns {Array} - the calculated bounds [L, T, R, B].
*/
function getItemBoundsIllustrator(item, geometric, bounds) {
var newBounds = [],
boundsKey = geometric ? 'geometricBounds' : 'visibleBounds';
if (undefined == item)
return;
if (
item.typename == 'GroupItem'
|| item.constructor.name == 'Array'
) {
var children = item.typename == 'GroupItem' ? item.pageItems : item,
contentBounds = [],
isClippingGroup = (item.hasOwnProperty('clipped') && item.clipped == true),
clipBounds;
for (var i = 0, child; i < children.length; i++) {
child = children[i];
if (
child.hasOwnProperty('clipping')
&& true === child.clipping
&& true !== child.stroked
&& true !== child.filled
)
// the clipping item
clipBounds = child.geometricBounds;
else
contentBounds.push(getItemBoundsIllustrator(child, geometric, bounds));
}
newBounds = combineBounds(contentBounds);
if (
isClippingGroup
&& clipBounds
&& newBounds
)
newBounds = intersectionOfBounds([clipBounds, newBounds]);
}
else if (
'TextFrame' === item.constructor.name
&& TextType.AREATEXT !== item.kind
) {
// get bounds of outlined text
var dup = item.duplicate().createOutline();
newBounds = dup[boundsKey];
dup.remove();
}
else if (item.hasOwnProperty(boundsKey)) {
newBounds = item[boundsKey];
}
// `bounds` will exist if this is a recursive execution
bounds = (undefined == bounds)
? bounds = newBounds
: bounds = combineBounds([newBounds, bounds]);
return bounds;
};
/**
* Returns the combined bounds of all bounds supplied.
* Works with Illustrator or Indesign bounds.
* @author m1b
* @version 2025-03-11
* @param {Array<bounds>} boundsArray - an array of bounds [L, T, R, B] or [T, L , B, R].
* @returns {bounds?} - the combined bounds.
*/
function combineBounds(boundsArray) {
var combinedBounds = boundsArray[0],
comparator;
if (/indesign/i.test(app.name))
comparator = [Math.min, Math.min, Math.max, Math.max];
else
comparator = [Math.min, Math.max, Math.max, Math.min];
// iterate through the rest of the bounds
for (var i = 1; i < boundsArray.length; i++) {
var bounds = boundsArray[i];
if (!bounds)
continue;
combinedBounds = [
comparator[0](combinedBounds[0], bounds[0]),
comparator[1](combinedBounds[1], bounds[1]),
comparator[2](combinedBounds[2], bounds[2]),
comparator[3](combinedBounds[3], bounds[3]),
];
}
return combinedBounds;
};
/**
* Returns the overlapping rectangle
* of two or more rectangles.
* NOTE: Returns undefined if ANY
* rectangles do not intersect.
* @author m1b
* @version 2024-09-05
* @param {Array<bounds>} arrayOfBounds - an array of bounds [L, T, R, B] or [T, L , B, R].
* @returns {bounds?} - intersecting bounds.
*/
function intersectionOfBounds(arrayOfBounds) {
var comparator;
if (/indesign/i.test(app.name))
comparator = [Math.max, Math.max, Math.min, Math.min];
else
comparator = [Math.max, Math.min, Math.min, Math.max];
// sort a copy of array
var bounds = arrayOfBounds
.slice(0)
.sort(function (a, b) { return b[0] - a[0] || a[1] - b[1] });
// start with first bounds
var intersection = bounds.shift(),
b;
// compare each bounds, getting smaller
while (b = bounds.shift()) {
// if doesn't intersect, bail out
if (!boundsDoIntersect(intersection, b))
return;
intersection = [
comparator[0](intersection[0], b[0]),
comparator[1](intersection[1], b[1]),
comparator[2](intersection[2], b[2]),
comparator[3](intersection[3], b[3]),
];
}
return intersection;
};
/**
* Returns true if the two bounds intersect.
* @author m1b
* @version 2024-03-10
* @param {Array} bounds1 - bounds array.
* @param {Array} bounds2 - bounds array.
* @param {Boolean} [TLBR] - whether bounds arrays are interpreted as [T, L, B, R] OR [L, T, R, B] (default: based on app).
* @returns {Boolean}
*/
function boundsDoIntersect(bounds1, bounds2, TLBR) {
if (undefined == TLBR)
TLBR = (/indesign/i.test(app.name));
return !(
TLBR
// TLBR
? (
bounds2[0] > bounds1[2]
|| bounds2[1] > bounds1[3]
|| bounds2[2] < bounds1[0]
|| bounds2[3] < bounds1[1]
)
// LTRB
: (
bounds2[0] > bounds1[2]
|| bounds2[1] < bounds1[3]
|| bounds2[2] < bounds1[0]
|| bounds2[3] > bounds1[1]
)
);
};
Edit 2025-03-11: added handling for empty clipping groups.
... View more
‎Mar 06, 2025
01:38 AM
Hi @Kevin33194884x0zc Brian's idea of using basic vertical alignment of the text frame seems to work. Also maybe using auto-size width will also help.
See my attached demo.indd document and .csv for the datamerge. I tried it with some random lines and it doesn't do too bad a job, at least as a starting point.
Or are we missing the point? If so, please clarify.
- Mark
P.S. There is further scope for a script to adjust the width based on the text, but we'd need to know much more about your actual data and other requirements to do that.
... View more
‎Mar 05, 2025
07:46 PM
@wckdtall I rarely see the benefit of overloading built-in methods. It is so easy to include an `indexOf` function that takes an array and another object, and the code is just as clear.
- Mark
... View more
‎Mar 05, 2025
07:43 PM
1 Upvote
Thanks again. There are benefits of standardization. Even I—a native English writer—have made changes to my language in the service of standardization. In Australia, we write "colour", but in code I always write "color" because it becomes too confusing using APIs that use "Color" and "ColorSpace", etc.
... View more
‎Mar 05, 2025
07:01 PM
Thanks @sttk3 I found that very interesting. In English we incorporate words from other languages all the time (not least from Japanese!) but what you describe is something for which we have no analogue that I can imagine.
> Some people, especially old people, use this notation for variable names, etc., but it is generally regarded as a bad practice.
May I ask what is good practice nowadays? I assume just normal written Japanese for variable names?
- Mark
... View more
‎Mar 05, 2025
02:36 PM
@wckdTall-2 That's interesting. Actually when I look at my code I do always use it inside a function, but I'm surprised it can't be set anywhere.
About VSCode, you just need to set the encoding on the file—easiest way is to click the bottom right corner where it shows the current encoding, and choose "Save with encoding" in the command bar at the top.
I'm pretty sure there was a case where I had to save a .csv file as "UTF-8 With Bom" for something, maybe to link to Indesign file? BOM is a few characters at the start of the file I think. I doubt you need to use it here, but I thought I'd mention it.
- Mark
... View more
‎Mar 05, 2025
02:30 PM
@Bobby Henderson I think this reflects the Japanese tendency to use katakana for borrowed or technical terms in modern contexts like software. I'm no expert, but use of the English phonetic spelling here might convey a sense of context where "shiro" might actually *feel* out of place? That last is just a speculation. Actually, we can ask an expert if not too busy: @sttk3 am I on the right track?
- Mark
... View more
‎Mar 05, 2025
06:12 AM
1 Upvote
@Sanyam Talwar thank you! I can confirm on MacOS 15.3.1, ID 20.2 the bug is fixed!
- Mark
... View more
‎Mar 04, 2025
06:40 PM
Hi @wckdTall-2 aside from ensuring the script file is encoded as UTF-8 (given that I can save and open it and the Japanese characters are fine I assume this is adequate), you can also add this to the start of your script and see if it helps:
$.appEncoding = 'UTF-8';
- Mark
... View more
‎Mar 04, 2025
05:49 PM
Thank you all for testing! 🙂 So I know that it isn't a problem local to my system.
@Eugene Tyson that is good information! My usual (naive?) approach is (a) I use Adobe Paragraph Composer until it gives a bad result (often!), and then (b) I switch to Adobe Single-line Composer just for that paragraph and do my best to fix it.
@Peter Kahrel thanks, that doesn't surprise me but I tried to find an existing bug report and nothing appeared in uservoice that I could find.
@Mike Witherell thanks for your comments... the demo document might be a little messy, as it was copy/pasted out part way during the cleaning up of someone else's document, but I had the paragraph styles working the way I wanted. This bug—now confirmed—appeared during a real use case and it was weird because it was easy to fix—just change almost anything: add a character, remove a character, change the table width, and the whole thing would go back to normal... only to fail again when another change triggered it again. And I couldn't find any reported instance of this issue, so I felt the need to post something here, even though I had found a workaround.
> But when would I validly do that? Override Paragraph Composer with Single Line Composer? I wouldn't do so, normally, would I?
Oh dear! This is literally what I *normally* do! See my comment to Eugene above. Is there a better way to fix a bad composition caused by Adobe Paragraph Composer?
However in the case of my demo document, it is ikely that I was fiddling around before I realised some of the parameters of the presumed-bug. But when I "Clear Overrides" on all text in the demo document, the bug is still evident.
> But if I edit the paragraph style Body to use Single-Line Composer, it functions correctly.
Yes! that is the workaround that I used. But I only needed to change the last paragraph before the span (the magenta paragraph).
> Interestingly, I notice the Heading and the Table Caption are set to Span; but the table styles are not set to span
Not too interesting... I set the Heading and Table Caption to span because they are in the text frame that has 2 columns, but the table styles—meaning the paragraph styles used for the table cells' text—don't spam because a cell doesn't have columns. As an experiment I set the table cell paragraph styles to span, but it didn't change anything, which makes sense.
I appreciate you all looking into it and confirming the bug. Thank you again!
- Mark
... View more
‎Mar 03, 2025
10:49 PM
Hi @punit_9859, I don't know that error, and I couldn't find the equivalent file on my system (MacOS, though).
So I don't have an answer, but here are some things to try:
• uninstall Illustrator and re-install.
• setting permissions on the file or folder(s) mentioned in the error message?
• try deleting that file(!) or just move it somewhere else
- Mark
... View more
‎Mar 03, 2025
10:44 PM
I was hoping at least one person could confirm that it isn't just on my system! 🙂
If anyone had a chance could you please open my demo document and see if you get the same result I got, shown in the gif above? Only 5 steps to test!
@Peter Kahrel @rob day @Marc Autret @Eugene Tyson @Mike Witherell
... View more
‎Mar 02, 2025
06:16 AM
Hi @Olivier24257193r870 could you please post an example of what you mean?
... View more
‎Mar 01, 2025
12:09 AM
1 Upvote
Hey @Eugene Tyson things don't always work out in the end, but that was great problem solving on your part. 🙂
... View more