Search code examples
c#itext7

Split overflow text in iText 7 paragraph


I have a document where the first page has three sections. The top and bottom section are required to be on the first page. The center section has dynamic text. I am trying to find a way to get all the text that will fit in the center section, set it, and then add the remaining to the continuation second page (if required).

I have looked at this S.O. answer, but it seems that it wouldn't allow for the bottom section to be placed where it needs to go.

Here is what I am trying to do.

using (var workStream = new MemoryStream())
{
    using (var pdfWriter = new PdfWriter(workStream))
    {
        using (var pdfDoc = new PdfDocument(pdfWriter))
        {
            var document = new Document(pdfDoc);
            var pageSize = pdfDoc.GetDefaultPageSize();
            var width = pageSize.GetWidth() - document.GetLeftMargin() - document.GetRightMargin();

            // *** First Top Section ***
            // ... variable creations removed for brevity ...
            document.Add(paragraph);
            document.Add(table);



            // *** CENTER SECTION ***
            // This section has a required float height of 325f



            // *** Third Bottom Section ***
            // ... table creation removed for brevity ...
            document.Add(table);

            // *** Create the second page if needed and add the overflow text ***

        }
    }
}

Solution

  • I found a solution that works for me. I am sure I could streamline it, but tempest fugit.

    So here is how I got the text for section 1:

    // Set the height of section 2 paragraph
    var section2Height = 325f;
    
    // Create a Text element with the desired text
    var tempText = new Text(myDesiredText).SetFont(font);
    
    // Create rectangle for the allowable space for section 2
    var rectangle = new Rectangle(width, section2Height);
    
    // Create PDFCanvas for the document
    var pdfCanvas = new PdfCanvas(pdfDoc, 1);
    
    // Create canvas space for adding the temp paragraph to for splitting
    var canvas = new Canvas(pdfCanvas, rectangle);
    
    // Set the temp text to a paragraph 
    var synopsis = new Paragraph(tempText).SetFixedLeading(12f);
    
    // Get the paragraph renderer
    var renderer = synopsis.CreateRendererSubTree();
    
    // Set the paragraph renderer parent to the canvas renderer
    renderer.SetParent(canvas.GetRenderer());
    
    // Process the renderer and get the layout result
    var result = renderer.Layout(new LayoutContext(new LayoutArea(1, rectangle)));
    
    // If the renderer is full, get all text, otherwise get the text that fits
    var page1 = result.GetStatus() == LayoutResult.FULL ? renderer : result.GetSplitRenderer();
    
    // Create a new paragraph for Section 2 (SYNOPSIS)
    var newParagraph = new Paragraph().SetFixedLeading(12f);
    
    // Set the Paragraph height and width
    newParagraph.SetWidth(width);
    newParagraph.SetHeight(section2Height);
    
    // Get the count of child renderers.  Each one is a new line
    var page1Count = page1.GetChildRenderers().Count;
    
    // Instantiate a string for the last renderer text
    var lastText = string.Empty;
    
    // Iterate through the child renderers
    for (var i = 0; i < page1Count; i++)
    {
        // Get the string value
        var text = page1.GetChildRenderers()[i].ToString();
    
        // Create a text element
        var t1 = new Text(text + Environment.NewLine).SetFont(font);
    
        // Add the Text element to the new paragraph
        newParagraph.Add(t1);
    
        // If this is the last line, store the text for later use
        if (i + 1 == page1Count)
            lastText = text;
    }
    
    // Get the index of the last string of text
    index = myDesiredText.IndexOf(lastText);
    
    // Get the remaining text base off the index and the last text string length
    var page2 = myDesiredText.Substring(index + lastText.Length);
    
    // If there is a string value...
    if (!string.IsNullOrEmpty(page2))
    {
        // Create a list of line returns
        var returnCharList = new List<string> { "\r", "\n" };
    
        // Remove the beginning line returns
        while (returnCharList.Contains(page2.Substring(0, 1)))
            page2 = page2.Substring(2);
    
    }
    
    // Add the new paragraph to the section
    document.Add(newParagraph);
    

    This I how I set the rest of the text to the next page

    // If there is a second page, build it out
    if (!string.IsNullOrEmpty(page2))
    {
        // Create the text element
        var page2Text = new Text(page2).SetFont(font);
    
        // Get the workable height for the paragraph minus the space for the page footer
        var page2Height = height - 30f;
    
        // Create page 2 paragraph
        var page2Paragraph = new Paragraph(page2Text).SetHeight(page2Height).SetFixedLeading(12f);
    
        // Add the paragraph to the document
        document.Add(page2Paragraph);
    
        // Create new pager
        pager = new Paragraph().AddTabStops(tabStops);
    
        // Set the page string for page 2
        pageBill = $"EBM - { RemoveBillSpaces(bsd.Bill.BillNumber)} - 2 of { totalPages }";
    
        // Create the text element
        pagerText = new Text(pageBill).SetFont(font).SetFontSize(fontSize_Small);
    
        // Add the tabs and text for the pager
        pager
        .Add(new Tab())
        .Add(new Tab())
        .Add(pagerText);
    
        // Add the pager to page 2
        document.Add(pager);
    }