Skip to main content
Skip table of contents

Large tables

The following example shows how you can add to a table little by little, in order to keep the memory footprint low.

Limitations

The use of large tables is not recommended in the following use cases:

  • Tables with complex content: For example, the use of form fields. This is because if the page is flushed too early, we can no longer update the needed data structures.

Extra Considerations:

  • PDF/A, PDF/UA: To ensure documents conform to these standards, flushing is disabled since we need to check a lot of things upon closing the document. For example, does all text actually use embedded fonts etc. Therefore, we must retain all the pages in memory to perform these conformance checks. This will generate a warning informing you page flushing could not be performed. However, using the large tables feature still benefits from general speed and memory improvements, because we return unused objects to the garbage collector.
    See https://stackoverflow.com/questions/78707405/itext7-large-table-pdf-a for more details on a real-world example.

incompletetable

JAVA

JAVA
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2023 Apryse Group NV
    Authors: Apryse Software.

    For more information, please contact iText Software at this address:
    sales@itextpdf.com
 */
package com.itextpdf.samples.sandbox.tables;

import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.properties.UnitValue;

import java.io.File;

public class IncompleteTable {
    public static final String DEST = "./target/sandbox/tables/incomplete_table.pdf";

    public static void main(String[] args) throws Exception {
        File file = new File(DEST);
        file.getParentFile().mkdirs();

        new IncompleteTable().manipulatePdf(DEST);
    }

    protected void manipulatePdf(String dest) throws Exception {
        PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
        Document doc = new Document(pdfDoc);

        // The second argument determines 'large table' functionality is used
        // It defines whether parts of the table will be written before all data is added.
        Table table = new Table(UnitValue.createPercentArray(5), true);

        for (int i = 0; i < 5; i++) {
            table.addHeaderCell(new Cell().setKeepTogether(true).add(new Paragraph("Header " + i)));
        }

        // For the "large tables" they shall be added to the document before its child elements are populated
        doc.add(table);

        for (int i = 0; i < 500; i++) {
            if (i % 5 == 0) {

                // Flushes the current content, e.g. places it on the document.
                // Please bear in mind that the method (alongside complete()) make sense only for 'large tables'
                table.flush();
            }

            table.addCell(new Cell().setKeepTogether(true).add(new Paragraph("Test " + i)
                    .setMargins(0, 0, 0, 0)));
        }

        // Flushes the rest of the content and indicates that no more content will be added to the table
        table.complete();

        doc.close();
    }
}

C#

C#
using System;
using System.IO;
using iText.Kernel.Pdf;
using iText.Layout;
using iText.Layout.Element;
using iText.Layout.Properties;

namespace iText.Samples.Sandbox.Tables
{
    public class IncompleteTable
    {
        public static readonly string DEST = "results/sandbox/tables/incomplete_table.pdf";

        public static void Main(String[] args)
        {
            FileInfo file = new FileInfo(DEST);
            file.Directory.Create();

            new IncompleteTable().ManipulatePdf(DEST);
        }

        private void ManipulatePdf(string dest)
        {
            PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
            Document doc = new Document(pdfDoc);

            // The second argument determines 'large table' functionality is used
            // It defines whether parts of the table will be written before all data is added.
            Table table = new Table(UnitValue.CreatePercentArray(5), true);

            for (int i = 0; i < 5; i++)
            {
                table.AddHeaderCell(new Cell().SetKeepTogether(true).Add(new Paragraph("Header " + i)));
            }

            // For the "large tables" they shall be added to the document before its child elements are populated
            doc.Add(table);

            for (int i = 0; i < 500; i++)
            {
                if (i % 5 == 0)
                {
                    // Flushes the current content, e.g. places it on the document.
                    // Please bear in mind that the method (alongside complete()) make sense only for 'large tables'
                    table.Flush();
                }

                table.AddCell(new Cell().SetKeepTogether(true).Add(new Paragraph("Test " + i)
                    .SetMargins(0, 0, 0, 0)));
            }

            // Flushes the rest of the content and indicates that no more content will be added to the table
            table.Complete();

            doc.Close();
        }
    }
}

Results

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.