Hi,
Hi,
Hi Manisha,
- (x, y) is at (0, 0)
- Width of this TOC is 6.5 inches and
- Height is a little more than 2.5 inches.
Hi,
Hi Manisha,
Hi Manisha,
LayoutEnumerator it = new LayoutEnumerator(doc);
// Field start of first TOC in the document
FieldStart fieldStart = null;
for (FieldStart start : (Iterable) doc.getChildNodes(NodeType.FIELD_START, true)){
if (start.getFieldType() == FieldType.FIELD_TOC){
fieldStart = start;
break;
}
}
// TOC can be anywhere in the document, including headers and table cells or it may be missing.
// We only interested in a TOC sitting in the main text story and not inside of a table.
// Also note that document can be invalid, for example, may not have field end or have it in different story.
// In this case code will crash, but we cannot assume anything about an invalid document anyway.
if (fieldStart == null ||
fieldStart.getAncestor(NodeType.CELL) != null ||
fieldStart.getAncestor(NodeType.BODY) == null)
return;
Field field = fieldStart.getField();
FieldSeparator separatorNode = field.getSeparator();
FieldEnd endNode = field.getEnd();
// Now we are interested in content between separator and end. Field result is sitting there.
// TOC has fields in the result too and fields in the result of those fields as well.
// { TOC | { HYPERLINK | First heading {PAGE} }¶{ HYPERLINK | Second heading {PAGE} }¶ … }
// Complicated but we do not care since field codes are not rendered and field charactes do not take space on the page either.
// It would be tricky to navigate document nodes in a search for the TOC content, instead we will navigate layout model
Object separator = collector.getEntity(separatorNode);
Object end = collector.getEntity(endNode);
// Maps page number to list of line bounding boxes relative to the page.
Hashtable pageMap = new Hashtable<Integer, List>();
// Remember line container of the field end. We need it to stop searching for TOC content.
it.setCurrent(end);
it.moveParent();
Object lastLine = it.getCurrent();
// Move to line container of the separator
it.setCurrent(separator);
it.moveParent();
// Collect rectangles of lines/rows inside TOC content
while (true)
{
Integer pageIndex = it.getPageIndex();
ArrayList rectList = (ArrayList) pageMap.get(pageIndex);
if (rectList == null)
{
rectList = new ArrayList();
pageMap.put(pageIndex, rectList);
}
rectList.add(it.getRectangle());
// Do not go beyond last line of TOC content
if (it.getCurrent() == lastLine)
break;
// Move to the next line in paragraph or next row in a table, if failed then need to find a logical link to the next entity.
// This implements moving along the logical order of the lines and rows in the document across page boundaries.
// Works for main text positions in a column, does not work within cell/header/footer, etc.
if (!it.moveNextLogical())
{
// Move to last span in a line or last cell in a row
it.moveLastChild();
// If moved to cell then descend to last span of it
if (it.getType() == LayoutEntityType.CELL)
{
// Note that last container in a cell is always a line.
it.moveLastChild();
it.moveLastChild();
}
// Since all spans are linked through the story we can move to the next logical span in the document.
it.moveNextLogical();
// Ascend to line
it.moveParent(LayoutEntityType.LINE);
// If inside a cell ascend to the topmost row
while (it.moveParent(LayoutEntityType.ROW)) { }
}
}
// For every page union line rectangles to get area covered by TOC
// Note that if TOC spans multiple columns on a page you would need to be smarter and union rectangles per column rather than page
Set keys = pageMap.keySet();
for (Integer key : (Iterable) keys) {
Integer pageIndex = key;
Rectangle2D rect = (Rectangle2D) (((ArrayList) pageMap.get(key)).get(0));
for (Rectangle2D r : (Iterable) ((ArrayList) pageMap.get(key)))
rect = rect.createUnion®;
System.out.println("Page: " + pageIndex + " & Rect: " + rect);
}