Rendering Lists in Irregular Columns Using iText / iTextSharp

Published 16 October 13 01:35 AM | Scott Mitchell

Today’s blog post is going to be a bit obscure, but I stumbled across this problem recently and found a workaround that I thought would be worth sharing for anyone else who found themselves in my place.

iText is an open-source library for programmatically creating PDF documents (iTextSharp is the .NET port of iText). I’ve written before on using iTextSharp to create PDF documents from an ASP.NET page, see:

There’s also an invaluable series of iTextSharp-related posts on Mike Brind’s blog, Create PDFs in ASP.NET.

I recently started work on a project that makes heavy use of iTextSharp to create rather complex PDF documents on the fly. One feature of iText is the ability to lay out text into columns. There are two flavors of columns available:

  • Simple columns – you create simple columns by defining a bounded rectangle, e.g., the lower left and upper right coordinates of the rectangle. The text then flows into the bounds of the column.
  • Irregular columns – with irregular columns you specify an array of coordinates for the left margin(s) and another array of coordinates for the right margin(s). With this approach you can define irregularly shaped columns in order to have the text flow around images and other document elements.

Mike’s Page Layout with Columns post provides a good overview of both simple and irregular columns.

One challenge I bumped into is how iText lays out the elements added to a column. There are two layout modes: composite mode and text mode. To be honest, I am not 100% clear on the fine differences between the two modes, but from my understanding the differences are as follows:

  • Composite mode allows you to add all sorts of elements and the layout defined by those added elements is what dictates the rendered layout. For example, you can add lists and tables paragraphs and other such elements to a column when using composite mode and the layout directives for the lists, tables and paragraphs are respected when the column is rendered.
  • With text mode, on the other hand, you are limited to adding only phrases to the column and any layout directives defined in the phrase(s) are ignored. Consequently, if you add three paragraphs in text mode they all run together, one after another, without space between each paragraph, without indentation, and so on.

Unfortunately, text mode and irregular columns are intertwined, meaning that if you are adding irregular columns you cannot use composite mode for those columns. The downside is that you cannot add lists, tables, or other richer document elements to an irregular column. Additionally, you have to add your own line breaks between paragraphs. For instance, if you examine the code in Mike’s Page Layout with Columns post you’ll see that in his irregular column example he adds a series of Phrases and ends the content of each phrase with two newline characters (\n) to create the whitespace between each paragraph.

So what if you need to add a bulleted or numbered list to an irregular columns, are you out of luck? Well, you’re out of luck if you want to add a List element and have it do the rendering but if you don’t mind doing to rendering yourself you can add your own list-like content. The following code snippet shows how to add both ordered and unordered lists.

First, let’s setup the irregular columns. The following code was lifted directly from Mike’s blog post:

Document doc = new Document();

try
{
    doc.SetMargins(45f, 45f, 60f, 60f);
    Font bodyFont = FontFactory.GetFont("Arial", 12, new BaseColor(0, 0, 0));

    FileStream output = new FileStream(Server.MapPath("~/MyIrregularColumnsExample.pdf"), FileMode.Create);
    PdfWriter writer = PdfWriter.GetInstance(doc, output);
    doc.Open();
    PdfContentByte cb = writer.DirectContent;
    ColumnText ct = new ColumnText(cb);


    float gutter = 15f;
    float colwidth = (doc.Right - doc.Left - gutter) / 2;

    float[] left = { doc.Left + 90f , doc.Top - 80f,
            doc.Left + 90f, doc.Top - 170f,
            doc.Left, doc.Top - 170f,
            doc.Left , doc.Bottom };

    float[] right = { doc.Left + colwidth, doc.Top - 80f,
            doc.Left + colwidth, doc.Bottom };

    ct.SetColumns(left, right);

    ct.Alignment = Element.ALIGN_JUSTIFIED;
    ct.AddText(new Phrase("Lorem ipsum dolor sit amet, ...\n\n", bodyFont));

This code starts be creating a Document and outputting the PDF to a file named MyIrregularColumnsExample.pdf on the file system. Next, the irregular column is defined through a series of left and right coordinates. These coordinates are such that the column will run on the left half of the page and wrap around a rectangle in the upper left corner where an image can be placed. If the intent isn’t clear, the screen shot below should help clarify things; also, you can read Mike’s blog post for details.

Next, the elements for the list are defined as a List<string>:

List<string> items = new List<string>();
items.Add("This is the first item");
items.Add("This is the next item");
items.Add("And here be the last item");

Next we’re ready to add the list! Here’s how you add an ordered list – simply loop through each item in the list and add some space and the appropriate number (1, 2, 3, …).

ct.AddText(new Phrase("Here is an ordered list:\n\n", bodyFont));

for (int i = 0; i < items.Count; i++)
{
    ct.AddText(new Phrase(string.Concat("     ", (i + 1), ".  "), bodyFont));
    ct.AddText(new Phrase(itemsIdea, bodyFont));

    if (i != items.Count - 1)
        ct.AddText(Chunk.NEWLINE);
}
            
ct.AddText(Chunk.NEWLINE);
ct.AddText(Chunk.NEWLINE);

For bulleted lists we can use the unicode character 0x2022 to render the bullet. Or you could choose alternative symbols.

ct.AddText(new Phrase("And here is an unordered list:\n\n", bodyFont));

for (int i = 0; i < items.Count; i++)
{
    ct.AddText(new Phrase(string.Concat("     ", '\u2022', "  "), bodyFont));
    ct.AddText(new Phrase(itemsIdea, bodyFont));

    if (i != items.Count - 1)
        ct.AddText(Chunk.NEWLINE);
}

ct.AddText(Chunk.NEWLINE);
ct.AddText(Chunk.NEWLINE);

That’s all there is to it! Here is a screen shot of the rendered PDF. Note the numbered and bulleted lists in an irregular column.

samplePdf

Happy Programming!

Filed under: ,

Comments

No Comments

Archives

My Books

  • Teach Yourself ASP.NET 4 in 24 Hours
  • Teach Yourself ASP.NET 3.5 in 24 Hours
  • Teach Yourself ASP.NET 2.0 in 24 Hours
  • ASP.NET Data Web Controls Kick Start
  • ASP.NET: Tips, Tutorials, and Code
  • Designing Active Server Pages
  • Teach Yourself Active Server Pages 3.0 in 21 Days

I am a Microsoft MVP for ASP.NET.

I am an ASPInsider.