Marc Autret
Guide
Marc Autret
Guide
Activity
Mar 02, 2025
07:05 AM
1 Upvote
in my quick test I did notice that app.colorTransform was returning 0..1 numbers Hi Mark, just keep in mind that the LAB color space is an exception to the rule, since it takes and returns L:0..100, a:-100..100, b:-100..100
... View more
Mar 02, 2025
06:52 AM
3 Upvotes
@Olivier24257193r870 Créer un bloc-texte et lui appliquer une rotation de +90°. (Le cas échéant, régler les options de Dimensionnement automatique à votre convenance.) Sélectionner le bloc-texte et lancer la commande suivante depuis un script jsx : app.selection[0].texts[0].properties = { characterRotation:-90 }; Saisir les caractères dans le bloc : Je ne sais pas si cela répond à l'objectif, mais on aura fait le maximum 😉 Marc
... View more
Feb 28, 2025
07:05 PM
3 Upvotes
Hi @árpádp3188668 By one of those obscure whims that belong only to the Adobe dev team, the method app.colorTransform(…) expects and returns numbers in 0…1 — except for the LAB color space which still uses the original colorValue ranges (L: 0…100, a: -100..100, b: -100..100). So you need to properly downscale (then upscale) the values found in your Swatch/Color objects, as dictated by the specific color spaces under consideration. Best is to have in your toolbox an adapter routine, like this: function colorTransform(/*num[]*/vals,/*str|ColorSpace*/from,/*str|ColorSpace*/to,/*int=0*/dec, a,k,i)
//----------------------------------
// vals :: array of numbers *as processed by Color.colorValue*, that is
// - [0..255, 0..255, 0..255] in RGB space
// - [0..100, 0..100, 0..100, 0..100] in CMYK space
// - [0..100, -128..127, -128..127] in LAB space
// - [0..360, 0..100, 0..100] in HSB space
// (Rem: MixedInk is not supported by app.colorTransform.)
// from :: source ColorSpace or key string ('RGB'|'CMYK'|'HSB'|'LAB')
// to :: dest. ColorSpace or key string ('RGB'|'CMYK'|'HSB'|'LAB')
// dec :: rounding decimal digits (use -1 to bypass rounding);
// default is 0, i.e. rounding to the nearest integer.
// Returns the converted values as a new array of 3 or 4 numbers in
// the expected ranges (i.e. as processed by Color.colorValue).
// => num[]
{
from = from.toString().toUpperCase();
to = to.toString().toUpperCase();
if( from==to ) return vals.slice();
switch( from )
{
case 'RGB':
// app.colorTransform() expects r,g,b values in 0..1 (!)
// -> divide by 255
a = [ vals[0]/255, vals[1]/255, vals[2]/255 ];
break;
case 'CMYK':
// app.colorTransform() expects c,m,y,k values in 0..1 (!)
// -> divide by 100
a = [ .01*vals[0], .01*vals[1], .01*vals[2], .01*vals[3] ];
break;
case 'HSB':
// app.colorTransform() expects h,s,b values in 0..1 (!)
// -> divide h by 360 and s,b by 100
a = [ vals[0]/360, .01*vals[1], .01*vals[2] ];
break;
case 'LAB':
// app.colorTransform() expects L,a,b values as given in original range,
// that is, L:0..100, a:-100..100, b:-100..100
a = vals.slice();
break;
default:
throw "Unsupported color space " + from;
}
try
{
a = app.colorTransform(a, ColorSpace[from], ColorSpace[to]);
}
catch(e)
{
throw "Unable to convert " + a + " from " + from + " to " + to + " [" + e + "]";
}
switch( to )
{
case 'RGB':
// app.colorTransform() returns r,g,b values in 0..1 (!)
// -> multiply by 255
a[0]*=255; a[1]*=255; a[2]*=255;
break;
case 'CMYK':
// app.colorTransform() returns c,m,y,k values in 0..1 (!)
// -> multiply by 100
a[0]*=100; a[1]*=100; a[2]*=100; a[3]*=100;
break;
case 'HSB':
// app.colorTransform() returns h,s,b values in 0..1 (!)
// -> multiply h by 360 and s,b by 100
a[0]*=360; a[1]*=100; a[2]*=100;
break;
case 'LAB':
// app.colorTransform() returns L,a,b values in original range,
// that is, L:0..100, a:-100..100, b:-100..100
default:;
}
if( 0 <= (dec|=0) )
{
k = Math.pow(10,dec);
for(i=a.length ; i-- ; a[i]=Math.round(k*a[i])/k );
}
return a;
}
// TEST: Transform the CMYK color [41,46,56,36] to RGB
// ---
var res = colorTransform( [41,46,56,36], 'CMYK', 'RGB' );
alert( res ); // => 113,97,82 Best, Marc
... View more
Feb 27, 2025
09:34 AM
2 Upvotes
Hi @SmythWharf By “library item” do you mean the library itself or some particular asset within such a library? I guess you're using the latter sense (?) As such, the Library object (container of assets) corresponds to an indl file — assuming local lib — and can be accessed and/or instanciated through app.libraries. This collection is empty if no library is presently available (=opened) in InDesign, but you can use app.libraries.add("/path/to/MyLibrary.indl"); to load a particular library. The name property of a Library instance — still assumed local — is the underlying file name. If your library is already loaded in ID, just use myLib = app.libraries.itemByName("MyLibrary.indl"); to get the corresponding specifier. From then, go to the Assets collection (myLib.assets) to navigate through the items this library contains. As usual, those elements are accessible by index or by name. So, if a particular asset is named template, you can easily retrieve a specifier using myAsset = myLib.assets.itemByName("template"); and then enjoy the Asset API. What you're probably looking after is myAsset.placeAsset(<where>), whose <where> argument refers to either a Document or Text instance, and which returns the placed item(s) as an array. The placeAsset behavior/target depends on myAsset.assetType, but in common cases you should expect this method to position the placed asset at its original location, that is, at the coordinates it owned when the InDesign user drag&dropped the item into the Library panel. (Changing the default placeAsset mechanism is an open question to me, although I admit I haven't experimented much in this field.) Best, Marc
... View more
Feb 24, 2025
02:26 PM
2 Upvotes
(…) Anyone have a more general implementation that, say, pops up a list of glyphs (configurable would be nice) or at least a code entry field, instead of being 2012-hardwired to one string? The InstantUnicode ‘responsive’ script may help — just type your codepoint in the form uHHHH and it instantly inserts the glyph at the insertion point: https://indiscripts.com/post/2020/03/instantunicode-insert-characters-by-typing-their-codepoint (Also supports code points beyond the BMP using the uppercase form U1HHHH.) Hope that helps. Best, Marc
... View more
Feb 17, 2025
07:28 AM
1 Upvote
An improved version (undoable, bugfix, etc.) is now available in the IdGoodies repo: → https://github.com/indiscripts/IdGoodies/blob/master/full/SelSetFrameHeightByLineCount.jsx Note that it also supports threaded frames ↓
... View more
Feb 16, 2025
08:22 PM
1 Upvote
Hi @m1b Amusing challenge! My two pennies: maybe we could make the whole setHeightByLineCount routine 100% agnostic. Here is a first draft that seems promising… https://gist.github.com/indiscripts/742c3760fe08beea37496e0db4fba4d2 Best, Marc
... View more
Jan 28, 2025
05:42 PM
4 Upvotes
Hi people, Until today and on all platforms, the low-level ExtendScript method Folder.prototype.create() was able to create a full path of non-existent subfolders within some root folder. For example, with the code var myFolder = new Folder( Folder.myDocuments + '/dir1/dir2/dir3' ); myFolder.create(); you were obtaining the creation of all required subfolders (dir1, dir2, dir3) in case of non-existence. This behavior was consistent across all versions of ExtendScript that we knew of, and on all systems. As of InDesign 20.1 (not 20.0.x), and specifically on macOS, the above code will not always produce the desired result. In fact, only the dir1 folder will be created (if it does not exist), or only dir2 (if dir1 exists but not dir2), and so on. In other words, myFolder.create() only creates the highest missing folder in the hierarchy—so it will only work correctly if all parent folders were already existing. A particular side effect is that, even if no errors are reported during the operation, a successfull myFolder.create() does not guarantee that myFolder.exists is then true! It's easy to imagine countless scenarios where this change (which in my opinion is a pure bug) will significantly affect the behavior of your scripts, including those already in circulation. Until Adobe fixes this issue or provides us with more details, it is possible to ‘patch’ the faulty method and restore its consistency. I just implemented this fix in the IdExtenso framework, but since I know that an infinitesimal number of developers use it, here the basic solution I suggest to you: //==========================================================================
// [FIX250129] Folder.prototype.create()
// Fixes the Folder creation bug in macOS + ID 20.1
//==========================================================================
if( 'Macintosh'==File.fs && 20.1 <= parseFloat(app.version) )
//----------------------------------
// Provides a patch to the method `Folder.prototype.create` so
// that it still creates the folder including all missing parents
// at the location given by the path property. Returns true if the
// folder was created successfully.
{
// Backup original method.
Folder.prototype.__create__ = Folder.prototype.create;
// Patch.
Folder.prototype.create = function create()
{
return this.exists ||
(
( null===this.parent || this.parent.create() )
&& this.__create__()
);
};
} Hope that helps. Best, Marc
... View more
Dec 04, 2024
06:41 PM
Can you explain what |^(?1) means? By @dublove Well, | is the alternation operator, ^ is the start-paragraph assertion, and (?1) is the actual fun part of the GREP expression: it reproduces the literal pattern from the 1st capturing parenthesis, that is, (\h+) in my example: (\h+)(?=\r|$)|^(?1) But if you use a different expression in the 1st parenthesis, say (\s+), then (?1) will reflect that change. So it's a convenient way to "factor out" syntactic elements within a GREP pattern. Best, Marc
... View more
Nov 23, 2024
04:50 PM
1 Upvote
For those who would be interested in handling this task with IndexMatic³: 1. Install the script in InDesign (the TRY version is ok for testing). 2. Open your documents/book. 3. From the Scripts panel, double-click IndexMatic3Try (or …Pro) and select your ‘target’ documents. 4. In Preferences > Generic Hyphens, add the En and Em dashes. (This makes the hyphen metacharacter more greedy.) 5. In Finder, select the Query List mode and click the preserve order button 6. Load the below query list (make sure you don't alter the syntax of the first line): //~ format /^(\d+) (.+)/ :: /^2 +(\d+[-\d:]*)/Ish => ^2 > $1
01 Genesis
02 Exodus
03 Leviticus
04 Numbers
05 Deuteronomy
06 Joshua
07 Judges
08 Ruth
09 1 Samuel
10 2 Samuel
11 1 Kings
12 2 Kings
13 1 Chronicles
14 2 Chronicles
15 Ezra
16 Nehemiah
17 Esther
18 Job
19 Psalms
20 Proverbs
21 Ecclesiastes
22 Song of Solomon
23 Isaiah
24 Jeremiah
25 Lamentations
26 Ezekiel
27 Daniel
28 Hosea
29 Joel
30 Amos
31 Obadiah
32 Jonah
33 Micah
34 Nahum
35 Habakkuk
36 Zephaniah
37 Haggai
38 Zechariah
39 Malachi
40 Matthew
41 Mark
42 Luke
43 John
44 Acts
45 Romans
46 1 Corinthians
47 2 Corinthians
48 Galatians
49 Ephesians
50 Philippians
51 Colossians
52 1 Thessalonians
53 2 Thessalonians
54 1 Timothy
55 2 Timothy
56 Titus
57 Philemon
58 Hebrews
59 James
60 1 Peter
61 2 Peter
62 1 John
63 2 John
64 3 John
65 Jude
66 Revelation 7. Generate the index. Best, Marc
... View more
Nov 22, 2024
05:15 PM
1 Upvote
Hi @Yousef Sobhy Ah, sorry, I thought it was just a sorting issue… Regarding automatic index creation based on Bible references, @AlanGilbertson mentioned above a tool which he describes as “the only tool that worked for (such) a difficult multi-volume project”. Maybe he's right and you should take a look. I would also mention IndexMatic3 (my own solution). In my experience (and especially that of the users I've talked to), it can extract these types of references from a book and produce the index with the desired formatting. It's basically a matter of sending the right queries (regular expressions) and creating the corresponding topics and entries. Note, however, that iX³ creates an independent index in InDesign (or txt, or xml, or idms), so it doesn't use the built-in Index feature. May I suggest that you test the TRY version to see if it meets your needs? Best, Marc
... View more
Nov 21, 2024
04:42 PM
1 Upvote
Hi @Yousef Sobhy Not sure this is exactly the ordering you're looking for, but SmartSort (free InDesign script) could help you get closer to the desired result, assumed you have a dedicated ¶-style for the head titles. Then 1. Select your Level1 style + “Sub-Sort Only”. 2. Turn on the Sort Numbers option. Smart Sort Test → https://indiscripts.com/category/projects/SmartSort Best, Marc
... View more
Nov 20, 2024
05:29 PM
3 Upvotes
Hi @dublove Try this: (\h+)(?=\r|$)|^(?1) In the above pattern, you could replace \h by a similar space metacharacter or class (e.g. \s, [[:space:]], [ \t], etc), but \h is usually considered the safest for that purpose. Best, Marc
... View more
Oct 21, 2024
05:39 AM
2 Upvotes
Great work Mark! Many nice settings (‘Divide Bins at Guides’, ‘Maximize’ options) will make this tool essential. FYI, a much more rudimentary approach without UI stuff and extra options: https://github.com/indiscripts/IdExtenso/tree/master/tests#rectpacktestjsx I only mention it for the purpose of comparing the two underlying algorithms. IdExtenso's RectPack module is based on github.com/mapbox/potpack, while yours relies on Jake Gordon's Binary Tree Bin Packing Algorithm which is probably the root reference of all existing solutions. The different implementations might be interesting to analyze in terms of performance. Best, Marc
... View more
Sep 16, 2024
07:32 AM
1 Upvote
DeliverGlyphs from Jean loup Fusz (FR) might help: https://le-blog.jloupf.fr/indesign/scripts/deliverglyphs-importer-rapidement-tous-les-glyphes-dune-police/ Best, Marc
... View more
Sep 03, 2024
03:26 AM
4 Upvotes
Hi, Coordinate spaces in IDML are detailed in the specification. The origin of the Spread space is its center point: Then you use ItemTransform and PathGeometry elements to get space-relative coordinates, in pt. More on this topic: https://indiscripts.com/blog/public/data/coordinate-spaces-and-transformations-5/CoordinateSpacesTransfos01-05.pdf Best, Marc
... View more
Jun 24, 2024
11:03 PM
1 Upvote
Hi all, For those who use IdExtenso, the module $$.PageRange supports the `f`, `ff` suffixes (reduxPair and reduxMore parameters). Full code here with all options explained: https://github.com/indiscripts/IdExtenso/blob/master/etc/$$.PageRange.jsxlib#L519 (Note: this algorithm is used in IndexMatic³.) Best, Marc
... View more
May 16, 2024
12:54 AM
2 Upvotes
Hi @pierret18811376 Image processing is the way to go, but here you might fake it using SCREEN blending mode on a BLACK background. Simple demo script: (function( orig, dup,g)
//----------------------------------
// Assuming a simple image container is selected on the page.
{
// 1. Basic enhancer.
(orig=app.selection[0]).properties =
{
strokeColor: "Black",
transparencySettings: {blendingSettings:{blendMode:+BlendMode.SCREEN}},
};
with( dup=orig.duplicate() )
{
graphics.everyItem().remove();
fillColor = "Black";
sendToBack();
}
// 2. Increase the B/W contrast if needed.
g = orig.parent.groups.add([orig,dup]);
(dup=g.duplicate()).properties =
{
transparencySettings: {blendingSettings:{blendMode:+BlendMode.COLOR_BURN}},
};
})(); Result: Best, Marc EDIT: Sorry for my intervention: I thought we were in the Scripting branch of the forum! Others have answered the substance of the question before me. My mistake.
... View more
May 15, 2024
07:40 AM
2 Upvotes
Hi @koskkim84 You obviously need something like csvContent.sort(); after the for loop. The script doesn't perform any sort in its current state. [The reason why it previously worked is probably that Folder.getFiles() was already returning sorted elements, which likely depends on system-level settings.] Best, Marc
... View more
May 01, 2024
06:41 AM
2 Upvotes
@ronnag74426794 Our colleague Laurent Tournier worked on this GREP fifteen years ago 😉 I guess this compact form should sum it up: ((?<=Uu[bhopqst])|(?<=A[cglmrstu]|B[aehikr]|C[adeflmnorsu]|D[bsy]|E[rsu]|F[emr]|G[ade]|H[efgos]|I[nr]|Kr|L[airu]|M[dgnot]|N[abdeiop]|Os|P[abdmortu]|R[abefghnu]|S[bcegimnr]|T[abcehilm]|Xe|Yb|Z[nr])|(?<=[BCFHIKNOPSUVWY]))[1-9]\d{0,1} (Edit: if you need more than two digits change the ending \d{0,1} into \d{0,2} or more — I don't know whether it's chemically relevant though.) Best, Marc
... View more
Apr 29, 2024
04:19 PM
1 Upvote
@Manan Joshi @Laubender I had to investigate in more depth the Text.styleOverridden and Text.textHasOverrides() features for a personal project. These results could complement and qualify some of the information presented here. → “Private Investigation into Style Overrides” (April 2024) Best, Marc
... View more
Apr 23, 2024
04:51 PM
3 Upvotes
Hi @Mauro Acciarri I don't know of any clean method to remove a nested PageItem from its container. The code below is just a stopgap solution based on Select/Cut/PasteInPlace. (function( doc,a,t,z)
{
doc = app.properties.activeDocument;
if( !doc ) return;
const REPL = +SelectionOptions.REPLACE_WITH;
app.scriptPreferences.enableRedraw = false;
// ---
for( z=0, a=doc.allPageItems ; t=a.pop() ; )
{
if( 'TextFrame' != t.constructor.name ) continue;
if( !t.parent.hasOwnProperty('paths') ) continue;
t.select(REPL); // May fail due to locked items, etc
app.selection.length && ( app.cut(), app.pasteInPlace(), ++z );
}
// ---
app.scriptPreferences.enableRedraw = true;
alert( z + ' text frames have been removed from hierarchy.')
})(); We obviously need a better approach… Maybe others will find it. Best, Marc
... View more
Apr 19, 2024
06:30 PM
3 Upvotes
@Andrew24943677v30i Without wanting to criticize my colleagues, I strongly discourage the proposed solution (which anyway seems problematic in other respects), simply because commands such that a.textContainers[0].parentPage.documentOffset within a custom sort function will explode the Scripting DOM as soon as the document contains a huge number of stories. In ExtendScript, a custom sort involves on average 5×N×Log(N) internal calls of the function. Note. - You should also take care of possible runtime errors (e.g. parentPage may be null, etc) and other issues (what about master pages?) As usual, the solution I suggest is based on generating safe UTF16 sort keys through one linear loop, calling the native Array.prototype.sort() and building the desired array. Safer and probably much faster with long documents. Here is a quick implementation [not tested in depth but you get the idea] function sortedStories(/*Document*/doc, K,ev,r,a,i,t)
{
// Init.
const CHR = String.fromCharCode;
K=doc.stories, ev=K.everyItem(), r=ev.id, a=ev.textContainers;
// Make sort keys -> r[i] :: <key> + storyId
for
(
i=r.length ; i-- ;
// ---
(t=a[i]).length // Have we a container?
&& (t=t[0].parentPage) // Have we a parent page?
&& 'Spread'===t.parent.constructor.name // Skip master pages!
? ( r[i]=CHR(1+t.documentOffset)+r[i] ) // Make 1st char sortable, add the ID.
: r.splice(i,1)
);
// Instant sort.
r.sort();
// Build array of sorted stories and return.
for( i=r.length ; i-- ; r[i]=K.itemByID(parseInt(r[i].slice(1),10)) );
return r;
};
var myStories = sortedStories(app.activeDocument);
// etc [EDIT] Still, this is certainly not the optimal way to reach the goal, but I wanted to illustrate my point while keeping the textContainers[0].parentPage.documentOffset approach proposed by @brian_p_dts Best, Marc
... View more
Mar 25, 2024
10:50 AM
2 Upvotes
Hi Pickory, Definitely just for fun: s = ((','+s).match(/,[^2][^,]*/g)||[]).join('').slice(1); 😉 Best, Marc
... View more
Mar 18, 2024
05:40 AM
1 Upvote
Hi @xstranhox55805267 Not sure this is relevant in your project but the script IndexMatic³ provides a Hits feature. The free version can report the 50 most repeated words, sorted by decreasing frequencies, and export results in TXT or CSV. You can also decide to exclude or include page numbers: → https://indiscripts.com/category/projects/IndexMatic Best, Marc
... View more
Mar 14, 2024
01:33 PM
(…) The 6th paramter, consideringRulerUnits, doesn‘t seem to work when the resize object is a page. The parameter consideringRulerUnits (in every method that supports it) only concerns the location or origin of the transformation (cf. Syntax of a Location), that is, the from parameter in the case of the resize() method. Best, Marc
... View more
Mar 14, 2024
03:44 AM
2 Upvotes
Also take note that myItem.override(targetPage) tends to shift the item when new pages have been added or for other obscure reasons. A generic bugfix is based on the targetPage.masterPageTransform matrix, whose nonzero translation components typically reflect the undesired shift: // Fixed override()
var mx = targetPage.masterPageTransform.matrixValues.slice(-2);
mx[0] += 'pt';
mx[1] += 'pt';
try{ myItem.override(targetPage).move(void 0, mx) }
catch(_){ } Best, Marc
... View more
Mar 07, 2024
08:53 AM
1 Upvote
Hi Mark, Difficult question! Of course the LayoutWindow object has bounds, but they are expressed in screen coordinates and (to my knowledge) there is no mapping from screen space to DOM coordinate spaces. These are totally different beasts. I haven't explored the question further, but perhaps an approach would be to create a transformation matrix yourself, at a specific time, from a known state of the ‘viewport’. For example, when you run View > Entire Pasteboard you get some fixed view that forcibly contains the whole active spread (and a few more pixels around!). At this particular time and zoom percentage, there is a virtual connection between the window bounds and the spread coordinate space, something like [k, 0, 0, k, tx, ty] in terms of transformation matrix. This solution seems extremely fragile though. Furthermore, it does not meet your goal (constraint 1) which implies that the screen↔DOM mapping should be determinated from any view state. Looks like a very hard problem 😞 Best, Marc
... View more
Mar 03, 2024
07:06 AM
3 Upvotes
Fun exercise! Here's one approach: function addCircles(/*(num|str)=auto*/diameter,/*uint=auto*/count, pg,DX,DY,dm,pp,shft,dx,dy,k,t)
//----------------------------------
// Add masking circles on the active page, that is, [Paper]-filled ovals.
// - diameter [opt] : diameter of each circle, either as a number in default
// measurement unit, or as a val-unit string e.g. "1.5mm" or "28pt". If not
// supplied, some diameter is automatically determined.
// - count [opt] : number of circles. If not supplied, a huge count is taken.
// => undef
{
pg = 'LayoutWindow'==(t=app.properties.activeWindow||0).constructor.name && (t.properties.activePage);
if( !(pg||0).isValid ){ alert("Please, make a page active."); return; };
// [REM] Assumes DX,DY have the same MU.
t = pg.bounds;
DX = t[3]-t[1];
DY = t[2]-t[0];
// Diameter
if( 'string' == typeof diameter && isFinite(t=parseFloat(diameter||'0')) && 0 < t )
{
dm = '?' != UnitValue(diameter).type && diameter;
}
else
{
t = +(diameter||0);
dm = 0 <= t && t < (DX>>>1) && t < (DY>>>1) && t;
}
dm || (dm=Math.min(DX,DY)/10); // Fallback?
// Oval props
pp =
{
transparencySettings:null,
strokeTransparencySettings:null,
fillTransparencySettings:null,
contentTransparencySettings:null,
textWrapPreferences:{textWrapMode:+TextWrapModes.NONE},
contentType:+ContentType.UNASSIGNED,
geometricBounds:[0, 0, dm, dm],
fillColor:'Paper',
fillTint:-1,
strokeWeight:0,
};
// Optimal count?
(count>>>=0) || (t=parseFloat(dm), count=Math.round(DX*DY/(t*t)));
// Create a set of sparse [dx,dy] shifts.
// (Reduces the number of close circles.)
const MR = Math.random;
const SQ = 1.2*Math.sqrt(count); // must be > √count and < 0xFFFE
const CHR = String.fromCharCode;
for( shft={} ; shft.__count__ < count ; shft[k]=[ DX*dx, DY*dy ] )
{
do{ dx=MR(), dy=MR(), k=CHR( 1+(SQ*dx)>>>0, 1+(SQ*dy)>>>0) }
while( shft.hasOwnProperty(k) );
}
// Generate the circles.
with( Window.splash=new Window('palette','',void 0,{borderless:true}) )
{
margins=50;
add('statictext',void 0,"Generating "+count+" circles...");
show();
update();
}
app.scriptPreferences.enableRedraw = false;
for each( t in shft ) pg.ovals.add(pp).move(t);
app.scriptPreferences.enableRedraw = true;
Window.splash.hide();
};
app.doScript
(
"addCircles( '25px', 200 )",
void 0, void 0, +UndoModes.ENTIRE_SCRIPT,
"Add Circles"
); Best, Marc
... View more
Feb 29, 2024
06:48 PM
1 Upvote
Hi @immijp49056642 Welcome to the club, you are entering the ExtendScript XML Nightmare 😉 I am not skilled enough in this area—Dirk and/or Loïc could probably help you, should they come across this discussion— but I strongly suspect that the biggest part of your problem is that your XML has all its elements namespaced due to the xmlns instruction at the root node: <xfdf xmlns="http://ns.adobe.com/xfdf/" …> This means that in expressions like xmlData.xpath("//field/value"), ‘field’ and ‘value’ are not the actual node names (only their local names I guess), but xpath is so poorly implemented in ExtendScript that you risk spending entire nights before finding a syntax (if any!) that could get around this difficulty. Maybe the best option would be to remove the whole xmlns stuff before entering the XML constructor (it's easy to detect and remove it at the string level), then to re-insert that very namespace if you need to output some XML file at the end of your process (?) There are certainly syntactic shortcuts to still access namespaced nodes, but I don't know them. If you can't bypass xmlns, the only solution I can see is the explicit and formal use of QName patches through the following scheme: // Get the ns and create a dedicated QName function.
var ns = '' + myXML.namespace();
var f = function(nme){ return QName(ns,nme) };
// Then use f('nodeName') wherever needed.
// Boring? I know! Now here are some tests you can run based on the above method: // Content of your XML file
var xmlFile = '''<?xml version="1.0" encoding="UTF-8"?>
<xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve">
<f href="Automation Form Test 1.pdf"/>
<fields>
<field name="File_1"><value>ABCDEF</value></field>
<field name="File_2"><value>Some Text</value></field>
<field name="File_3"><value>Some more text</value></field>
</fields>
<ids original="00054952DF51F14FB50D88332A014639" modified="B16CF70A22E4F341A0F65B6E7D370758"/>
</xfdf>'''
;
var xmlData = XML(xmlFile);
// Create your dedicated QName function.
var ns = ''+xmlData.namespace();
var f = function(nme){ return QName(ns,nme) };
var x;
// Get the <value> from all fields
x = xmlData.descendants( f('value') );
alert( x.toXMLString() ); // show nodes
alert( x.text().toXMLString() ); // show inner texts
// Get the <value> node of the 2nd <field> i.e. index 1.
x = xmlData.descendants( f('field') )[1].descendants( f('value') );
alert( x.toXMLString() ); // show node
alert( x.text().toXMLString() ); // show inner text
// Select the <field> whose @name is 'File_3' and gets its <value>.
x = xmlData.descendants( f('field') ).xpath("node()[@name='File_3']").descendants( f('value') );
alert( x.toXMLString() ); // show node
alert( x.text() ); // show inner text No doubt much better approaches exist. Hopefully our colleagues will outline them below. Best, Marc
... View more