Search code examples
javapdfitextrenderingitext7

How to render two tables simultaneously (tables are having content more than single page) using iText7


I need to add 2 tables on 2 parallel columns starting from page 1, and both tables have content more than a single page. Table1 runs on left half of page and table2 runs on right half. I started rendering table 1 and it overflows. Now before proceeding to next page, I want to start rendering table 2 (adding new page makes previous page inaccessible). The implementation of this in iText5 was done using CoulmnText. In iText5, I used 'ColumnText.hasMoreText(status)' to check the overflowing nature of table. But in iText7 this approach is different. This is the sample code in iText7 which i tried to solve the problem stated.

public void createPdf(String dest) throws FileNotFoundException {
    Rectangle[] columnsEven = {new Rectangle(200, 100, 100, 500), new Rectangle(500, 100, 100, 500)};

    PdfWriter writer =new PdfWriter(DEST);
    PdfDocument pdfDoc = new PdfDocument(writer);
    Document document = new Document(pdfDoc);

    Table table1 = new Table(2);
    Table table2 = new Table(2);

    String cellContent1="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam metus elit, ornare et justo nec, ornare dignissim leo. Praesent in egestas erat. Donec id nunc libero. Nullam aliquam sodales sollicitudin. Proin ac egestas nunc. Nunc et suscipit augue. Curabitur porta tempor nunc vel suscipit. Suspendisse imperdiet nunc id quam aliquet fermentum. Pellentesque ut dolor non odio congue blandit. Morbi laoreet magna quam, quis suscipit nunc pulvinar et. Nullam sit amet semper odio, sagittis dictum erat.\n"+

        "Curabitur sagittis arcu turpis, et tincidunt quam congue in. Nullam vitae felis id dui fringilla tincidunt. Nulla ullamcorper nisi non arcu fermentum, eu tempor lectus mattis. Aliquam leo purus, vulputate et ornare in, tincidunt sit amet mi. Sed sollicitudin et sapien vel hendrerit. Morbi id sodales sapien. In non nisl velit. Mauris maximus sodales lectus, ac dignissim elit cursus ac. Nulla viverra, velit sed cursus tincidunt, ex risus posuere diam, lobortis congue metus eros at lorem. Cras a ligula tortor. Vestibulum efficitur diam eros, eget dapibus magna cursus sed.\n"+
        "Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam ut velit pretium diam vestibulum consectetur. Praesent dignissim id sapien eget ultrices. Nam non libero iaculis dolor mattis egestas et quis leo. Sed vitae libero a enim viverra finibus sit amet sed nulla. Sed vitae sem hendrerit, posuere justo sagittis, placerat justo. Aenean felis nisi, tincidunt faucibus sem at, egestas interdum nibh. Curabitur venenatis neque nec volutpat mollis. Phasellus vel tellus ut nisl consequat gravida. Maecenas eget ligula vestibulum, finibus turpis a, hendrerit est. Cras eleifend mollis commodo.\n"+

        "Morbi quam velit, elementum nec turpis porttitor, venenatis sagittis nunc. Sed et nisi ipsum. Maecenas eget tellus in dui condimentum dictum a tempus sem. Maecenas consectetur nisl sit amet accumsan volutpat. Sed dictum massa vitae urna aliquam imperdiet. Nam at ex feugiat dolor vestibulum vehicula. Nullam leo magna, porta ac ex vitae, malesuada fermentum turpis. Donec vel turpis quis ligula feugiat molestie quis at nisi. Quisque efficitur velit odio, id rhoncus diam varius eu. Duis dui mi, scelerisque at faucibus ac, sodales sed est. Sed dictum aliquet semper.\n"+


        "Sed erat ipsum, vehicula nec magna sed, aliquam volutpat lorem. Integer et auctor nisl, at auctor lorem. Nam bibendum urna nec quam cursus, vitae rhoncus justo semper. Morbi posuere dapibus quam vel euismod. Morbi id maximus augue, ut vulputate turpis. Cras posuere auctor justo, in ultricies nunc tincidunt id. Sed luctus nisl lacus, in facilisis erat ultricies id. Aliquam erat volutpat. Morbi accumsan lectus nec dolor ultricies dignissim. Sed quis finibus lectus.\n"+

                "Pellentesque aliquet ex eget cursus accumsan. In ultrices tempus orci sed ultrices. Maecenas lectus nunc, consectetur ac suscipit et, tempus rutrum ipsum. Nulla accumsan tincidunt dignissim. Sed malesuada sapien elit, ac semper urna maximus at. Nunc eleifend tortor nec ligula auctor, sit amet sagittis turpis sagittis. Nam laoreet justo sed gravida iaculis. Fusce ornare quam quis arcu gravida rutrum. Aliquam vitae augue sit amet nisi finibus ullamcorper. Proin quis placerat velit. Integer malesuada erat nec massa tempus pretium.";

    Cell cell = new Cell().add(new Paragraph("INDIA"));
    table1.addCell(cell);   
    table2.addCell(cell);
    cell = new Cell().add(new Paragraph(cellContent1));
    table1.addCell(cell);
    table2.addCell(cell);
    drawTables(pdfDoc, document, new Table[] {table1, table2}, columnsEven);
    document.close();

}

public void drawTables(PdfDocument pdfDoc, Document document, Table[] tables , Rectangle[] rects) {
    // for table 1
    DocumentRenderer renderer1= new MyColumnDocumentRenderer(document, new Rectangle[] {rects[0]});
    document.add(table1);
    // for table 2
    DocumentRenderer renderer2= new MyColumnDocumentRenderer(document, new Rectangle[] {rects[1]});
    document.add(table2);

}
public class MyColumnDocumentRenderer extends DocumentRenderer {
    protected Rectangle column;

    public MyColumnDocumentRenderer(Document document, Rectangle[] column) {
        super(document);
        this.column = column[0];        
    }

    @Override
    protected LayoutArea updateCurrentArea(LayoutResult overflowResult) {
        if(overflowResult!=null && overflowResult.getStatus()== LayoutResult.PARTIAL) {

            column = new Rectangle(300, 100, 200, 600);
        }
        super.updateCurrentArea(overflowResult);


        return (currentArea = new RootLayoutArea(currentPageNumber, column.clone()));
    }

I am migrating iText5 to iText7. Can you suggest me the best approach to implement the problem stated?

I need some help on the questions below as well. Is it possible to process document.add(table1) and document.add(table2) simultaneously? Can we save state of document renderer for one table while we render other table?


Solution

  • You can always do this in many passes: open the document in stamping mode (with PdfReader and PdfWriter), add the necessary content, close the document, then open the new version of the document, add more content, close the document and so on.

    There implementations that are available out of the box do not support your case of simultaneous layouting of several objects across many pages. However, the whole layouting framework is flexible enough so if you dig into the source code a but you can extend from existing implementations and only modify them slightly to achieve your case.

    We will extend from ColumnDocumentRenderer to have access to some protected fields and will add a possibility to go back to the first page in the renderer. Please note that in order for this solution to work we need to pass immediateFlush=false to parent's constructor which will increase the memory footprint a bit. Please also note that the solution depends on the implementation details a bit so it might stop working even during a patch upgrade. But this is more of a theoretical possibility, just keep an eye on it.

    private static final class ResettingColumnDocumentRenderer extends ColumnDocumentRenderer {
        public ResettingColumnDocumentRenderer(Document document, Rectangle[] columns) {
            super(document, false, columns);
        }
    
        public void resetToFirstPage() {
            currentArea = null;
            currentPageNumber = 0;
            nextAreaNumber = 0;
        }
    }
    

    Now that we have a custom document renderer implementation we can generalize your drawTables method to support case of rendering of N tables:

    public void drawTables(Document document, Table[] tables , Rectangle[] rects) {
        for (int i = 0; i < tables.length; i++) {
            ResettingColumnDocumentRenderer renderer = new ResettingColumnDocumentRenderer(document, new Rectangle[] {rects[i]});
            document.setRenderer(renderer);
            document.add(tables[i]);
            renderer.resetToFirstPage();
            renderer.flush();
        }
    }
    

    Finally, here is the outer calling code, with almost no modifications compared to your original version:

    public void createPdf() throws FileNotFoundException {
        Rectangle[] columnsEven = {new Rectangle(70, 100, 200, 500), new Rectangle(350, 100, 200, 500)};
    
        PdfWriter writer =new PdfWriter("C:/Users/Alexey/Desktop/23423423.pdf");
        PdfDocument pdfDoc = new PdfDocument(writer);
        Document document = new Document(pdfDoc);
    
        Table table1 = new Table(2);
        Table table2 = new Table(2);
    
        String cellContent1="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam metus elit, ornare et justo nec, ornare dignissim leo. Praesent in egestas erat. Donec id nunc libero. Nullam aliquam sodales sollicitudin. Proin ac egestas nunc. Nunc et suscipit augue. Curabitur porta tempor nunc vel suscipit. Suspendisse imperdiet nunc id quam aliquet fermentum. Pellentesque ut dolor non odio congue blandit. Morbi laoreet magna quam, quis suscipit nunc pulvinar et. Nullam sit amet semper odio, sagittis dictum erat.\n"+
    
                "Curabitur sagittis arcu turpis, et tincidunt quam congue in. Nullam vitae felis id dui fringilla tincidunt. Nulla ullamcorper nisi non arcu fermentum, eu tempor lectus mattis. Aliquam leo purus, vulputate et ornare in, tincidunt sit amet mi. Sed sollicitudin et sapien vel hendrerit. Morbi id sodales sapien. In non nisl velit. Mauris maximus sodales lectus, ac dignissim elit cursus ac. Nulla viverra, velit sed cursus tincidunt, ex risus posuere diam, lobortis congue metus eros at lorem. Cras a ligula tortor. Vestibulum efficitur diam eros, eget dapibus magna cursus sed.\n"+
                "Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam ut velit pretium diam vestibulum consectetur. Praesent dignissim id sapien eget ultrices. Nam non libero iaculis dolor mattis egestas et quis leo. Sed vitae libero a enim viverra finibus sit amet sed nulla. Sed vitae sem hendrerit, posuere justo sagittis, placerat justo. Aenean felis nisi, tincidunt faucibus sem at, egestas interdum nibh. Curabitur venenatis neque nec volutpat mollis. Phasellus vel tellus ut nisl consequat gravida. Maecenas eget ligula vestibulum, finibus turpis a, hendrerit est. Cras eleifend mollis commodo.\n"+
    
                "Morbi quam velit, elementum nec turpis porttitor, venenatis sagittis nunc. Sed et nisi ipsum. Maecenas eget tellus in dui condimentum dictum a tempus sem. Maecenas consectetur nisl sit amet accumsan volutpat. Sed dictum massa vitae urna aliquam imperdiet. Nam at ex feugiat dolor vestibulum vehicula. Nullam leo magna, porta ac ex vitae, malesuada fermentum turpis. Donec vel turpis quis ligula feugiat molestie quis at nisi. Quisque efficitur velit odio, id rhoncus diam varius eu. Duis dui mi, scelerisque at faucibus ac, sodales sed est. Sed dictum aliquet semper.\n"+
    
    
                "Sed erat ipsum, vehicula nec magna sed, aliquam volutpat lorem. Integer et auctor nisl, at auctor lorem. Nam bibendum urna nec quam cursus, vitae rhoncus justo semper. Morbi posuere dapibus quam vel euismod. Morbi id maximus augue, ut vulputate turpis. Cras posuere auctor justo, in ultricies nunc tincidunt id. Sed luctus nisl lacus, in facilisis erat ultricies id. Aliquam erat volutpat. Morbi accumsan lectus nec dolor ultricies dignissim. Sed quis finibus lectus.\n"+
    
                "Pellentesque aliquet ex eget cursus accumsan. In ultrices tempus orci sed ultrices. Maecenas lectus nunc, consectetur ac suscipit et, tempus rutrum ipsum. Nulla accumsan tincidunt dignissim. Sed malesuada sapien elit, ac semper urna maximus at. Nunc eleifend tortor nec ligula auctor, sit amet sagittis turpis sagittis. Nam laoreet justo sed gravida iaculis. Fusce ornare quam quis arcu gravida rutrum. Aliquam vitae augue sit amet nisi finibus ullamcorper. Proin quis placerat velit. Integer malesuada erat nec massa tempus pretium.";
    
        Cell cell = new Cell().add(new Paragraph("INDIA"));
        table1.addCell(cell);
        table2.addCell(cell);
        cell = new Cell().add(new Paragraph(cellContent1));
        table1.addCell(cell);
        table2.addCell(cell);
        drawTables(document, new Table[] {table1, table2}, columnsEven);
        document.close();
    
    }