How to reduce redundant code when adding content at absolute positions?

Tags: coordinate systemiText 7

This is part of a vb.net app that uses the itextsharp library:

Dim cb As PdfContentByte = writer.DirectContent
cb.BeginText()
cb.SetFontAndSize(Californian, 36)
cb.ShowTextAligned(PdfContentByte.ALIGN_CENTER,
    "CERTIFICATE OF COMPLETION", 396, 397.91, 0)
cb.SetFontAndSize(Bold_Times, 22)
cb.ShowTextAligned(PdfContentByte.ALIGN_CENTER, name, 396, 322.35, 0)
cb.SetFontAndSize(Bold_Times, 16)
cb.ShowTextAligned(PdfContentByte.ALIGN_CENTER,
    _hours + " Hours", 297.05, 285.44, 0)
cb.SetFontAndSize(Bold_Times, 16)
cb.ShowTextAligned(PdfContentByte.ALIGN_CENTER,
    _dates, 494.95, 285.44, 0)
cb.SetFontAndSize(Bold_Times, 16)
cb.ShowTextAligned(PdfContentByte.ALIGN_CENTER, _class1, 396, 250.34, 0)
If Not String.IsNullOrWhiteSpace(_class2) Then
    cb.SetFontAndSize(Bold_Times, 16)
    cb.ShowTextAligned(PdfContentByte.ALIGN_CENTER, _class2, 396, 235.34, 0)
End If
cb.SetFontAndSize(Copper, 16)
cb.ShowTextAligned(PdfContentByte.ALIGN_CENTER,
    _conf_num + _prefix + " Annual Conference " + _dates, 396, 193.89, 0)
cb.SetFontAndSize(Bold_Times, 13)
cb.ShowTextAligned(PdfContentByte.ALIGN_CENTER, "Some Name", 396, 175.69, 0)
cb.SetFontAndSize(Bold_Times, 10)
cb.ShowTextAligned(PdfContentByte.ALIGN_CENTER,
    "Some Company Manager", 396, 162.64, 0)
cb.EndText()
Plenty of lines in this snippet look awfully redundant and in my opinion, this can't be the cleanest way to do things. Unfortunately, I can't figure out how to create a separate function to which I can simply pass some parameters, such as string, x_Cord, y_Cord, tilt. Such a function would then perform the necessary operations on the PdfContentByte.

Posted on StackOverflow on Nov 23, 2012 by Skindeep2366

You're adding content "the hard way". If I were you, I'd write a separate class/factory/method that creates a Paragraph with the content. For instance:

FontProgramFactory.registerFont(californianSrc, "Californian");
FontProgramFactory.registerFont(californianSrc, " Bold_times");
protected PdfFont f1 = PdfFontFactory.createRegisteredFont("Californian", PdfEncodings.WINANSI, false);
protected PdfFont f2 = PdfFontFactory.createRegisteredFont("Bold_times", PdfEncodings.WINANSI, false);
public Paragraph getCustomParagraph(String name, int hours, ...) {
  Paragraph p = new Paragraph();
  p.add(new Text(" ").setFont(f1) .setFontSize(36));
  p.add(new Text(name).setFont(f2) .setFontSize(16));
  ...
 return p;
}

Then I would use ColumnDocumentRenderer to set the areas where I want the data to appear:

ColumnDocumentRenderer renderer = new ColumnDocumentRenderer(doc, new Rectangle[]{new Rectangle(20, 100, 250, 700), new Rectangle(300, 100, 250, 700)});
doc.setRenderer(renderer);
Paragraph p = getCustomParagraph(name, hours, ...);
doc.add(p);

Or if you only need to write one line that doesn't need to be wrapped it's better to use Canvas.showTextAligned() method:

PdfPage page = pdfDoc.addNewPage();
PdfCanvas pdfCanvas = new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdfDoc);
Paragraph p = getCustomParagraph(name, hours, ...);
new Canvas(pdfCanvas, pdfDoc, page.getPageSize())
    .showTextAligned(p, 200, 500, pdfDoc.getPageNumber(page), TextAlignment.CENTER, VerticalAlignment.MIDDLE, 0);

The approach you've taken works, but... it involves writing PDF syntax almost "manually". That's more difficult and therefore more error-prone. You already discovered that, otherwise you wouldn't ask the question ;-)

Click this link if you want to see how to answer this question in iText 5.