I'm working with iText 7 on building pdf documents programatically. One of the features that I need to support is the ability to have barcodes in the footer that contains the current page and the total number of pages.
My approach so far is to introduce a page end event handler that will leave a placeholder on the documents footer with a pdf form x object. This event handler also keeps track of all the barcode placeholders that were added to the document and what page they were added on.
When the document is finished writing out all the content, it then loops over all the placeholders, regenerating the barcode with the final content (page x of y) and adds it to where the original barcode was placed.
This seems to work well for the first few pages, but when it hits about 8 / 10 pages the barcodes stop rendering.
It appears that the loop that handles regenerating the barcodes is being handled before last 2 page end events are handled. This seems to be a known thing where some events are being called with the document closed (itext7 end_page events are called when document is closed).
I've tried calling document.flush on the document object to see if I could get the events to fire before the loop is called, but this doesn't appear to have any difference.
I've also tried not immediately flushing the document (both with flushing and not flushing document and the individual pages), but I wasn't sure how to trigger the events, so no barcodes showed up when I did this.
I was hoping that calling flush after all the content has been added would force the events through the handler. Is there some other way to force the events through before closing the document? Or is there a better way to handle this requirement?
Here is the full code sample that I am working with for dotnet and itext7.2.5 nuget package. Any idea if there is a work around for being able to add a different barcode image to each of the footers?
void Main()
{
var path = System.IO.Path.GetTempFileName();
using var ms = new FileStream(path, FileMode.Create);
var pdfDocument = new PdfDocument(new PdfWriter(ms)).SetTagged();
var document = new Document(pdfDocument);
List<BarcodePlaceHolder> placeholders = new();
var pageEndHandler = new PageEndEventHandler(placeholders);
pdfDocument.AddEventHandler(PdfDocumentEvent.END_PAGE, pageEndHandler);
// render the content
for (int i = 0; i < 10; i++)
{
if (i > 0)
document.Add(new AreaBreak(AreaBreakType.NEXT_PAGE));
var paragraph = new Paragraph("page content");
document.Add(paragraph);
}
// handle all the page counts
foreach (var placeholder in placeholders)
{
var pdfCanvas = new PdfCanvas(placeholder.Placeholder, pdfDocument);
placeholder.Barcode.SetCode($"page {placeholder.PageNumber} of {pdfDocument.GetNumberOfPages()}");
var rectangle = new Rectangle(0, 0, placeholder.Placeholder.GetWidth(), placeholder.Placeholder.GetHeight());
pdfCanvas.AddXObjectFittedIntoRectangle(placeholder.Barcode.CreateFormXObject(pdfDocument), rectangle);
}
document.Close();
}
public class BarcodePlaceHolder {
public PdfFormXObject Placeholder {get; set;}
public int PageNumber {get; set;}
public Barcode128 Barcode {get; set;}
}
public class PageEndEventHandler : IEventHandler
{
List<BarcodePlaceHolder> _placeHolders;
public PageEndEventHandler(List<BarcodePlaceHolder> placeholders)
{
_placeHolders = placeholders;
}
public void HandleEvent(Event @event)
{
if (@event is not PdfDocumentEvent docEvent) return;
PdfDocument pdf = docEvent.GetDocument();
PdfPage page = docEvent.GetPage();
Barcode128 barcode = new Barcode128(pdf);
barcode.SetCode("page 0 of 0");
barcode.SetSize(12);
Rectangle rect = barcode.GetBarcodeSize();
PdfFormXObject formXObject = new PdfFormXObject(new Rectangle(rect.GetWidth(), rect.GetHeight() + 10));
Image barcodeImage = new Image(formXObject);
// create the canvas that we can add the details to
Canvas canvas = new Canvas(page, new Rectangle(0, 0, page.GetPageSize().GetWidth(), 25));
canvas.Add(barcodeImage);
_placeHolders.Add(new BarcodePlaceHolder() { PageNumber = pdf.GetPageNumber(page), Placeholder = formXObject, Barcode = barcode });
}
}