Itextsharp - check to see if adding an element will create a new page

16,198

Solution 1

Have a look at Page Events, in particular onStartPage and/or onEndPage to determine if you have to change the margins of the document.

Please note that these examples are for the Java version, but the conversion to iTextSharp should be straightforward.

Solution 2

Try this code:

public const string pageBreakHtmlMarker = "<!-- pageBreak -->";
public MemoryStream htmlToPdf(string html)
{
    MemoryStream msOutput = new MemoryStream();
    string[] sep = new string[] { pageBreakHtmlMarker };
    string[] arrHtml = html.Split(sep, 9999, StringSplitOptions.RemoveEmptyEntries);
    htmlToPdf(arrHtml, ref msOutput);
    return msOutput;
}
private void htmlToPdf(string[] arrHtmlPages, ref MemoryStream msOutput)
{
    using (Document document = new Document(PageSize.A4, 30, 30, 30, 30))
    {
        using (HTMLWorker worker = new HTMLWorker(document))
        {
            PdfWriter writer = PdfWriter.GetInstance(document, msOutput); // writer to listen doc ad direct a XML-stream to a file            
            document.Open();
            worker.StartDocument();
            foreach (string html in arrHtmlPages)
            {
                TextReader reader = new StringReader(html); // parse the html into the document
                worker.Parse(reader);
                document.Add(Chunk.NEXTPAGE);
            }
            worker.EndDocument();
        }
    }
}
Share:
16,198
Big The Dave
Author by

Big The Dave

Updated on June 05, 2022

Comments

  • Big The Dave
    Big The Dave almost 2 years

    I'm using ITextSharp to convert an HTML document into PDF. I use HTMLWorker.ParseToList and loop through each item in turn. That works fine, however the first page is required to have different margin sizes to the subsequent pages. I can do this by calling MyDocument.NewPage() and calling MyDocument.SetMargins().

    My problem occurs when trying to detect the page transitions.

    I can use a loop to keep track of page transitions, then call NewPage() and reset the margins, however, this can only happen once I've actually added a paragraph that wraps onto a new page, leaving an entire page that's practically white-space.

    I need a way of pre-emptively detecting if the page will change if I add a certain Paragraph object. I've tried using ColumnText.Go(true) to simulate it (and if the result of that is ColumnText.NO_MORE_COLUMN, then make it a page break), unfortunately that appears to be flakey at best, and tends to detect page breaks in entirely the wrong places.

    Here's my current code:

                ColumnText simulation = new ColumnText(Writer.DirectContent);
                simulation.SetSimpleColumn(Writer.PageSize);   
                bool FirstPage = true;
                foreach (var item in ItemList)
                {
                    var para = new Paragraph("", Normal);
                    para.AddAll(item.Chunks);                    
                    para.SpacingAfter = 10;
                    foreach (Chunk c in item.Chunks)
                    {
                        simulation.AddText(c);
                    }
                    if(FirstPage) {
                        int simresult = simulation.Go(true);
                        if(simresult == (int)ColumnText.NO_MORE_COLUMN)
                        {
                            textDocument.SetMargins(100,100,100,100);
                            textDocument.NewPage();    
                            FirstPage = false;                 
                        }
                    }
    
                    textDocument.Add(para);
                }
    

    This results in it not detecting a page break until the end of page 2. Which is no good.

    The only way I've found to get it working is to HALF the height going into simulation.SetSimpleColumn.

    It works, but I don't know why, and honestly, that's no good. If anyone can give me any insight that'd be great.



    Thanks to Alexis I've worked it out. The ITextSharp follows the Java event model pretty thoroughly, which is annoying since I was looking for events in the Writer and Document directly. First I had to create a class that overrode PdfPageEventHelper:

    internal class MainTextEventsHandler : PdfPageEventHelper
    {
        public override void OnStartPage(PdfWriter writer, Document document)
        {
            document.SetMargins(document.LeftMargin, document.LeftMargin, document.TopMargin, document.BottomMargin); //Mirror the horizontal margins
            document.NewPage(); //do this otherwise the margins won't take
        }
    }
    

    Next, I set the PageEvent property of the Writer object, and I modified my loop to remove the simulation.

            Writer.PageEvent = new MainTextEventsHandler();
            foreach (var item in ItemList)
            {
                var para = new Paragraph("", Normal);
                para.AddAll(item.Chunks);
                /* per-paragraph stuff here */
                para.SpacingAfter = 10;                    
                textDocument.Add(para);
            }