Copy link to clipboard
Copied
Hi, I've been searching for a way to get the coordinates of a table column or cell. The reason I need this data is that I want to place another object inline with a specific column/cell. I've seen some forums discussing the idea of using createOutlines() to tempoarily create an outline that I can use for it's geometricBounds property, but that doesn't seem to work (The exception I get is "NoPathCreated"). Any idea on how I could get this data would be appreciated!
Hi @Phil 815, I've written a script that includes a function getCellBounds. See this thread for the script. To get the bounds of a column (assuming that bounds of a cell wouldn't be adequate), you could calculate it similarly to the way getTableBounds function works. Let me know how you go.
- Mark
Copy link to clipboard
Copied
Hi @Phil 815, I've written a script that includes a function getCellBounds. See this thread for the script. To get the bounds of a column (assuming that bounds of a cell wouldn't be adequate), you could calculate it similarly to the way getTableBounds function works. Let me know how you go.
- Mark
Copy link to clipboard
Copied
These answers were extremely helpful and got me to a solution. Thank you!
Copy link to clipboard
Copied
Hi @Phil 815 ,
also look into the TableCellBox.jsx script by Marc Autret:
https://github.com/indiscripts/IdGoodies/blob/master/snip/TableCellBox.jsx
The Magic Parent Bounding Box
Marc Autret, August 04, 2022
https://www.indiscripts.com/post/2022/08/magic-parent-bounding-box
And a discussion in German that inspired Marc Autret at hilfdirselbst.ch:
https://www.hilfdirselbst.ch/foren/Koordinaten_einer_Tabellenzelle_P583998.html
Regards,
Uwe Laubender
( Adobe Community Expert )
Copy link to clipboard
Copied
Thanks @Laubender, that script looks very sophisticated! 🙂
Copy link to clipboard
Copied
The script is really amazing, but I managed to crash InDesign multiple times using it.
Im pretty sure the crash is caused by a table, that is inside an anchored text frame:
TextFrame → anchored TextFrame → Table crashes every time
TextFrame → Table works reliably
Copy link to clipboard
Copied
Copy link to clipboard
Copied
I did use TableCellBox.jsx
Copy link to clipboard
Copied
Perhaps @Marc Autret will update their excellent script to work with anchored tables. In the meantime, I have modified my getCellBounds function to handle this case:
/**
* Gets the bounds of the selected cell.
* Draws a rectangle just for demonstration.
* @author m1b
* @discussion https://community.adobe.com/t5/indesign-discussions/table-s-position-amp-scripting/m-p/13555533
*/
function main() {
var doc = app.activeDocument,
selectedCell = getCell(app.selection[0]);
if (
selectedCell == undefined
|| !selectedCell.isValid
) {
alert('Please select a table cell and run script again.');
return;
}
var bounds = getCellBounds(selectedCell);
// draw a rectangle with the calculated bounds
var justForShowing = doc.layoutWindows[0].activePage.rectangles.add({ geometricBounds: bounds, fillColor: doc.swatches[4] });
justForShowing.transparencySettings.blendingSettings.opacity = 50;
}; // end main
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, "Get Cell Bounds Demo");
/**
* Returns the geometricBounds of the cell;
* @author m1b
* @version 2023-06-07
* @param {Cell} cell - an Indesign Table Cell.
* @param {String} [boundsType] - can be 'geometricBounds' or 'visibleBounds' (default: 'geometricBounds').
* @returns {Array<Number>}
*/
function getCellBounds(cell, boundsType) {
app.scriptPreferences.measurementUnit = MeasurementUnits.POINTS;
boundsType = boundsType || 'geometricBounds';
if (!cell.hasOwnProperty('index'))
throw Error('getCellBounds failed: bad cell parameter.');
var table = cell.parent;
while (table.constructor.name != 'Table')
table = table.parent;
table.insertLabel('findMe', '1');
var textFrame = table.parent;
while (textFrame.parent.constructor.name == 'Character') {
// inside anchored frame
textFrame = textFrame.parent.parentTextFrames[0];
}
var cellID = cell.id,
dupTextFrame = textFrame.duplicate(),
dupTable;
// find the table in dup text frame
tableSearch:
for (var i = 0; i < dupTextFrame.tables.length; i++) {
if (dupTextFrame.tables[i].extractLabel('findMe') == '1') {
dupTable = dupTextFrame.tables[i];
break tableSearch;
}
}
if (dupTable == undefined) {
// find the table in anchored text frames
tableSearch:
for (var i = 0; i < dupTextFrame.textFrames.length; i++) {
for (var j = 0; j < dupTextFrame.textFrames[i].tables.length; j++)
if (dupTextFrame.textFrames[i].tables[j].extractLabel('findMe') == '1') {
dupTable = dupTextFrame.textFrames[i].tables[j];
break tableSearch;
}
}
}
if (dupTable == undefined)
throw Error('getCellBounds failed: Could not find table in duplicate.');
// convert cell to graphic, so we can get the bounds
var dupCell = dupTable.cells.itemByID(cellID);
dupCell.convertCellType(CellTypeEnum.GRAPHIC_TYPE_CELL);
var bounds = dupCell.rectangles[0].geometricBounds;
// clean up
table.insertLabel('findMe', '');
dupTextFrame.remove();
// add strokeWidths
if (boundsType === 'visibleBounds') {
bounds[0] -= cell.topEdgeStrokeWeight;
bounds[1] -= cell.leftEdgeStrokeWeight;
bounds[2] += cell.bottomEdgeStrokeWeight;
bounds[3] += cell.rightEdgeStrokeWeight;
}
else if (boundsType === 'geometricBounds') {
bounds[0] -= cell.topEdgeStrokeWeight / 2;
bounds[1] -= cell.leftEdgeStrokeWeight / 2;
bounds[2] += cell.bottomEdgeStrokeWeight / 2;
bounds[3] += cell.rightEdgeStrokeWeight / 2;
}
return bounds;
};
/**
* Attempts to return a Cell, given an object.
* @author m1b
* @version 2023-02-06
* @param {InsertionPoint|Text|Cells|Table} obj - an object related to a Cell.
* @returns {Cell}
*/
function getCell(obj) {
if (obj == undefined)
return;
if (obj.constructor.name == 'Cell')
return obj;
if (obj.parent.constructor.name == 'Cell')
return obj.parent;
if (
obj.hasOwnProperty('cells')
&& obj.cells.length > 0
)
return obj.cells[0];
};
Copy link to clipboard
Copied
Thanks @C330 S for the bug report. I get a crash when the cell/table belongs to an anchored frame and itself owns an anchored object.
Here are the three “simple” cases I've tested so far:
I'll try to fix case #3 asap…
Can you share an IDML so I can investigate your own example?
Best,
Marc
Copy link to clipboard
Copied
@m1b and @Marc Autret thanks a lot for your answers.
I might not be able to look into it before next week, but I will definitely give you feedback. I will also check, if I can give you an IDML (it’s work for a customer).
Mark, your observation absolutely makes sense, as I have an anchor mark in each of these tables (actually finding these anchored objects is the starting point of my script).
Copy link to clipboard
Copied
Hi all,
I didn't find any error in TableCellBox.jsx, matrices and transformations are properly calculated even in the Anchored-To-Anchored case reported by @C330 S. However, the line that makes ID crash is this one:
sto.move(MX.loBEG,cell.texts[0].insertionPoints[0]);
which helps us identify the InDesign bug tucked behind the issue: given a Text objet source that contains an anchored object (AO), any attempt to move it into another AO will crash ID. The bug is not even related to Table or Cell objects.
// Tested in InDesign CS6/CC, Win10
// (see animation below)
// ---
TFS = app.activeDocument.textFrames;
source = TFS.itemByName('source').texts[0]; // Text: contains the anchor
host = TFS.itemByName('host'); // TextFrame: 'host' frame
dest = host.textFrames.itemByName('dest'); // TextFrame: 'dest' frame
//source.move(LocationOptions.AT_BEGINNING,host); // WOULD BE OK
source.move(LocationOptions.AT_BEGINNING,dest); // --> ID crash
The bug seems specific to the move() method, regardless of whether it is invoked from a Text or a parent Story. Using duplicate() instead appears to work, so we could use that as a workaround (before removing the temporary frame). But duplicate() has a serious cost: it creates separate objects (new ids, etc.), which breaks the cellBox routine's commitment to remain transparent 😕
Maybe our friend @Laubender will find a way around this bad compromise. [Of course there is no hope that Adobe cares about this bug and tries to fix it. They focus on serious things: renaming masterpage to parentpage, etc]
Best,
Marc
Copy link to clipboard
Copied
Update: The InDesign bug at the root of the issue is circumvented in TableCellBox.jsx v3 released today.
Best,
Marc
Copy link to clipboard
Copied
Hi m1b and Marc,
I finally got some time to test both scripts. My layout looks like this:
I have a text frame containing a table (»innerhalb …«). The table contains another anchored text frame with an ID (»0226«). The frame with the table is anchored in the main text flow (»Was bedeutet …«). (This actually makes sense, although it may not look like it.)
Both scripts work fine, InDesign didn’t crash a single time, the results were (mostly) perfect.
In my case, @m1b’s getCellBounds fails sometimes, when the text flows into a second line within a cell:
The calculated size (grey rectangle) is not high enough (this is the ›mostly‹ part). Sometimes it is very small, sometimes it is almost high enough (like in the gif above). The cell is not created by merging two cells into one (I don’t know the proper english InDesign term for this).
Marc’s TableCellBox always returns the correct size:
Unfortunately Marc’s script is so cryptic to me, that I wasn’t able to modify it to suit my needs.
My goal is, to write coordinates after the ID (coordinates of the bottom right corner of the cell containing the anchor mark). I don’t need very high precision. If the result is off by less than one millimetre, its’s fine for me.
I found out that the variable q contains these coordinates after line 161.
So if I just return q, instead of the statement in line 167, I have everything, I need. – Almost.
@Marc Autret would you be so kind as to give me a hint about these two things?
Thank you very much,
Martin
Copy link to clipboard
Copied
Hi @C330 S
Thanks for your feedback.
(…)
Unfortunately Marc’s script is so cryptic to me, that I wasn’t able to modify it to suit my needs.
My goal is, to write coordinates after the ID (coordinates of the bottom right corner of the cell containing the anchor mark). I don’t need very high precision. If the result is off by less than one millimetre, its’s fine for me.
I found out that the variable q contains these coordinates after line 161.
So if I just return q, instead of the statement in line 167, I have everything, I need. – Almost.
- Firstly, I du not understand how to prevent the yellow rectangle from beeing drawn.
- Secondly, the coordinates, I get are to small by about 5 point.
I can easily correct the values, but I’m wondering, if I’m missing something.(…)
By @C330 S
1. Basically, you can just proceed as follows:
– get the result object ret=cellBox(targetCell);
– store ret.box.geometricBounds, or visibleBounds, etc., for further processing;
– remove the box: ret.box.remove().
2. But keep in mind that ret.box.geometricBounds or similar properties may be misleading:
so it is usually safer to rely on the coordinates that the function returns. I've just enhanced the returned structure to make it a bit more practical:
• first, you can now skip the rectangle creation by passing false as 2nd arg: ret=cellBox(targetCell,false).
• also, ret now exposes the properties topLeft, topRight, bottomLeft, bottomRight, which translate each anchor in spread coordinate space (that is, in points and relative to the center point of the spread). As long as the spread is not itself transformed, you can use those coordinates for processing data regardless of the rulers origin and state.
Edit. — “Secondly, the coordinates, I get are to small by about 5 point.” The current version of cellBox compensates the edge stroke weight of the cell(s) in order to produce coordinates in the sense of a geometric path. Maybe that's the reason why you have such an offset. If you strictly need the inner geometry (disregarding stroke weight), comment the lines
(t=pp.leftEdgeStrokeWeight||0) && (lt[0]-=t/2); // Left edge shift.
(t=pp.topEdgeStrokeWeight||0) && (lt[1]-=t/2); // Top edge shift.
(…)
(t=pp.rightEdgeStrokeWeight||0) && (rb[0]+=t/2); // Right edge shift.
(t=pp.bottomEdgeStrokeWeight||0) && (rb[1]+=t/2); // Rottom edge shift.
If, on the contrary, you are looking for the outer geometry (fully including stroke weight), change t/2 into t.
Hope that helps.
Best,
Marc
Copy link to clipboard
Copied
@Marc Autretthank you very much!
I suspected the solution could be something as easy as ret.box.remove(), but I couldn’t find it.
I like the version with the argument false even better. ret.bottomRight gives me exactly the position I need. Now I only have to figure out, how to convert to page coordinates in millimeters, but I’m sure I’ll get there.
Regarding the »coordinates too small by 5pt«:
I don’t think I wrote it clearly: I compared the coordinates in variable q with the coordinates of the generated yellow rectangle. Since the rectangle dosn’t have a border, I thought, the coordinates would be identical. The thinking error must be mine, as the script clearly produces the right result (the rectangle).
In the end it doesn’t matter, because the new version already gives the correct numerical result.
Best regards,
Martin
Copy link to clipboard
Copied
@Marc Autretthank you very much!
(…) Now I only have to figure out, how to convert to page coordinates in millimeters, but I’m sure I’ll get there.
By @C330 S
The returned structure has topLeft, topRight, bottomLeft, and bottomRight coordinates computed relative to the Spread coordinate space, which does not match, in general, the custom ruler system (zeroPoint, units, etc).
• Strictly regarding the POINTS→MILLIMETERS conversion, you can use the UnitValue class:
var mmValue = UnitValue(ptValue,'pt').as('mm');
• Now to convert spread space coordinates into page or ruler coordinates, the PDF https://indiscripts.com/tag/CST may help. In simple cases (=untransformed page and spread) it's just a matter of translating [x,y] according to the vector [dx,dy] that goes from the origin of the page (or ruler system) to the center point of the spread (i.e., the origin of the spread space).
Best,
Marc
Copy link to clipboard
Copied
What exactly do you mean by "inline"?
Copy link to clipboard
Copied
@Marc Autret said: "[Of course there is no hope that Adobe cares about this bug and tries to fix it. They focus on serious things: renaming masterpage to parentpage, etc]"
Hi Marc,
just voted to fix the bug at InDesign UserVoice:
Moving Anchoring Text to Anchored Object Crashes InDesign
Marc Autret, June 08, 2023
https://indesign.uservoice.com/forums/913162-adobe-indesign-sdk-scripting-bugs-and-features/suggesti...
Posted code there:
Code:
// Tested in ID CS6 and CC
// (see animation)
const BEG = LocationOptions.AT_BEGINNING;
var TFS = app.activeDocument.textFrames;
source = TFS.itemByName('source').texts[0]; // Text: contains the anchor
host = TFS.itemByName('host'); // TextFrame: 'host' frame
dest = host.textFrames.itemByName('dest'); // TextFrame: 'dest' frame
source.move(BEG,dest); // --> ID crash
//source.move(BEG,host); // WOULD BE OK
//source.duplicate(BEG,dest); // WOULD BE OK
Thanks Marc for reporting the bug.
PS: Attached the InDesign test document with the named text frames.
Regards,
Uwe Laubender
( Adobe Community Expert )