1
votes

In iText PDF 7, I am using the .layout method of the Table renderer to determine whether a table will break across a page.

However, when I add the .getSplitRenderer (returned from the layout result object) as a child of the Documents's renderer, I get this error: "java.lang.IndexOutOfBoundsException".

I'm using iText PDF version 7.1.7 in its Java incarnation. The last three entries in the stacktrace are:

java.util.ArrayList$SubList.rangeCheck(ArrayList.java:1225)
java.util.ArrayList$SubList.get(ArrayList.java:1042)
com.itextpdf.layout.renderer.TableBorders.processAllBordersAndEmptyRows(TableBorders.java:139)

Here is a bare-bones version of the code that triggers the error:

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PdfWriter pdfWriter = new PdfWriter(outputStream);
PdfDoc pdfDoc = new PdfDocument(pdfWriter);
PageSize pageSize = new PageSize(612, 792);
Document doc = new Document(pdfDoc, pageSize);

Table table = new Table([50, 50, 50]);
for (int i = 0; i < 1000; i++) {
    for (int j = 0; j < 3; j++) {
        Cell cell = new Cell();
        cell.setHeight(100);
        table.addCell(cell);
    }
}

LayoutContext context = new LayoutContext(doc.getRenderer().getCurrentArea().clone());
TableRenderer tableRenderer = (TableRenderer)table.createRendererSubTree();
LayoutResult result = tableRenderer.setParent(doc.getRenderer()).layout(context);

if (result.getStatus() == result.PARTIAL) {
    tableRenderer = (TableRenderer) result.getSplitRenderer();
    doc.getRenderer().addChild(tableRenderer); // this is where the error occurs
}
1
Please share enough code to reproduce the issue. - mkl
Thanks for the suggestion, @mkl. I have edited the post accordingly. - Michael Gurney

1 Answers

1
votes

When you add a child to the DocumentRenderer it will layout and draw it automatically. It is not possible to layout a renderer several times in most cases (although what can be improved here is the exception type and message).

If you want to draw the part that fits immediately you can use the following line:

tableRenderer.draw(new DrawContext(pdfDocument, new PdfCanvas(pdfDocument.getPage(doc.getRenderer().getCurrentArea().getPageNumber()))));

Complete if expression:

if (result.getStatus() == LayoutResult.PARTIAL) {
    tableRenderer = (TableRenderer) result.getSplitRenderer();
    tableRenderer.draw(new DrawContext(pdfDocument, new PdfCanvas(pdfDocument.getPage(doc.getRenderer().getCurrentArea().getPageNumber()))));
}

It might have some drawbacks in complex cases though, so if you are dealing with complex layout or tagged documents I would recommend using binary search to determine the amount of content that still fits and add that content as an element to Document instance still.

An approach that is between those two is adding the table completely and then removing the extra pages from PdfDocument. In this case keep in mind that you will have to recreate the DocumentRenderer because it does not keep track of low level events like page removal from PdfDocument.