Create and Deliver ASP.NET Barcoded PDF Contact Lists with iTextSharp

How to generate a barcoded PDF contact list from a Datatable using iTextSharp and ASP.NET

You can quickly develop a real love-hate relationship with iTextSharp, but the fact is that it can generate just about any kind of PDF output you want. The trick is going through the pain of studying and learning to use its API. The documentation is really for iText (the original Java version) and although the syntax is very similar, it can be a real pain figuring out how to do things. There are a few pretty good tutorials on the web if you feel inclined to google for it.

Some time ago, I wrote this article about filling out a form by writing directly on an existing PDF. But this article is about how to generate a custom contact list in PDF format from scratch.

For starters, we can look at the ASP.NET Demo page I use to deliver the PDF, as it is very simple:

  protected void Page_Load(object sender, EventArgs e)
        {    
            byte[] boit = CreatePDF.DeliverPDF();
           //  File.WriteAllBytes(@"C:\temp\test.pdf", boit);

            Response.ContentType = "application/pdf";
            Response.AddHeader("content-disposition", "attachment;filename=file.pdf");
            Response.Buffer = true;
            Response.Clear();
            Response.OutputStream.Write(boit,0,boit.Length );
            Response.OutputStream.Flush();
            Response.End();
        }

You can see above that I also had the option to write the completed PDF to the file system, but that is commented out.


Now to the nitty-gritty:

using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Web;
using iTextSharp.text;
using iTextSharp.text.pdf;

namespace PDFDemo
{
    public static class CreatePDF
    {
         public static byte[] DeliverPDF()
        {
           // Let's create a demo Datatable first:
            DataTable dt = new DataTable();
             dt.Columns.Add("ID");
            dt.Columns.Add("NameFirst");
            dt.Columns.Add("NameLast");
            dt.Columns.Add("address");
            dt.Columns.Add("address2");
            dt.Columns.Add("city");
            dt.Columns.Add("state");
            dt.Columns.Add("zipcode");
            dt.Columns.Add("phone");
            for (int i = 1; i < 200; i++)
            {
                DataRow row = dt.NewRow();
                row.ItemArray = new object[] {"LAU" +i.ToString(),"Joe","Banana" +i.ToString( ),i.ToString( ) + " High St.", "#"+i.ToString( ),"Zippidee","OH","83210","315 434-123" + i.ToString().Substring( 0,1)};
                 dt.Rows.Add(row);
            }

            // OK we have some data, now let's create the PDF            
            Document document = new Document(PageSize.LETTER, 10, 10, 10, 10);
            MemoryStream ms = new MemoryStream();
            PdfWriter wr = PdfWriter.GetInstance(document, ms);
             document.Open();
            BaseFont bf = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, false);
            Font tbf = new Font(bf, 9, Font.NORMAL, Color.BLACK);
            int ctr = 0;
            foreach (DataRow row in dt.Rows)
            {
                PdfPTable table = new PdfPTable(4);
                table.WidthPercentage = 100;
                table.SpacingBefore = 2;
                table.SpacingAfter = 2;

                float[] widths = new float[] { 1f, 1.5f, .75f, .75f };
                table.SetWidths(widths);
                PdfPCell cell = new PdfPCell(new Phrase("___________________________________________________________________________________"));
                cell.Colspan = 4;
                cell.Border = 0;
                cell.Padding = 1;
                cell.HorizontalAlignment = 0;
                 table.AddCell(cell);// the horizontal line  

                var img = CreateBarcodeImage(Convert.ToString(row["ID"]));
                PdfPCell cell2 = new PdfPCell(img);
                cell2.Border = 0;
                cell2.Padding = 1;
                table.AddCell(img);
                Phrase phrName = new Phrase((String)row["NameFirst"] + " " + (string)row["NameLast"], tbf);
                PdfPCell cell3 = new PdfPCell(phrName);
                cell3.Border = 0;
                cell3.Padding = 0;
                table.AddCell(cell3);
                PdfPCell cell4 = new PdfPCell(new Phrase("Recall", tbf));
                cell4.Border = 0;
                cell4.Padding = 0;
                table.AddCell(cell4);
                PdfPCell cell5 = new PdfPCell(new Phrase("Results", tbf));
                cell5.Border = 0;
                cell5.Padding = 0;
                 table.AddCell(cell5);

                  // this should be the next row
                PdfPCell cell6 = new PdfPCell(new Phrase(("   ")));
                cell6.Border = 0;
                cell6.Padding = 0;
                table.AddCell(cell6);

                string addr = (string)row["address"] + " " + (string)row["address2"];
                PdfPCell cell7 = new PdfPCell(new Phrase(addr, tbf));
                cell7.Border = 0;
                cell7.Padding = 0;
                table.AddCell(cell7);

                PdfPCell cell8 = new PdfPCell(new Phrase("[ ] YES", tbf));
                cell8.Border = 0;
                cell8.Padding = 0;
                table.AddCell(cell8);

                PdfPCell cell9 = new PdfPCell(new Phrase("[ ] Not Home", tbf));
                cell9.Border = 0;
                cell9.Padding = 0;
                table.AddCell(cell9);

                PdfPCell cellspc = new PdfPCell(new Phrase("    "));
                cellspc.Border = 0;
                cellspc.Padding = 0;
                 table.AddCell(cellspc);

                  // new row - citystzip
                string citystzip = (string)row["city"] + ", " + (string)row["state"] + " " + (string)row["zipcode"];

                PdfPCell cell10 = new PdfPCell(new Phrase(citystzip, tbf));
                cell10.Border = 0;
                cell10.Padding = 0;
                table.AddCell(cell10);

                PdfPCell cell11 = new PdfPCell(new Phrase("[ ] NO", tbf));
                cell11.Border = 0;
                cell11.Padding = 0;
                table.AddCell(cell11);

                PdfPCell cell12 = new PdfPCell(new Phrase("[ ] Deceased", tbf));
                cell12.Border = 0;
                cell12.Padding = 0;
                 table.AddCell(cell12);

                  // next row barcode number, nothing, []Undecided, []Wrong Number

                PdfPCell cell13 = new PdfPCell(new Phrase(Convert.ToString(row["ID"]), tbf));
                cell13.Border = 0;
                cell13.Padding = 0;
                table.AddCell(cell13);

                PdfPCell cell14 = new PdfPCell(new Phrase(" "));
                cell14.Border = 0;
                cell14.Padding = 0;
                table.AddCell(cell14);

                PdfPCell cell15 = new PdfPCell(new Phrase("[ ] Undecided", tbf));
                cell15.Border = 0;
                cell15.Padding = 0;
                table.AddCell(cell15);

                PdfPCell cell16 = new PdfPCell(new Phrase("[ ] Wrong No.", tbf));
                cell16.Border = 0;
                cell16.Padding = 0;
                 table.AddCell(cell16);

                  // last row
                PdfPCell cell17 = new PdfPCell(new Phrase(" "));
                cell17.Border = 0;
                cell17.Padding = 0;
                table.AddCell(cell17);

                string phone = row["Phone"] == DBNull.Value ? "" : (string)row["Phone"];
                PdfPCell cell18 = new PdfPCell(new Phrase(phone, tbf));
                cell18.Border = 0;
                cell18.Padding = 0;
                table.AddCell(cell18);

                PdfPCell cell19 = new PdfPCell(new Phrase(""));
                cell19.Border = 0;
                cell19.Padding = 0;
                table.AddCell(cell19);

                PdfPCell cell20 = new PdfPCell(new Phrase(""));
                cell20.Border = 0;
                cell20.Padding = 0;
                 table.AddCell(cell20);
                 document.Add(table);
                 ctr++;
                 if (ctr % 8 == 0)
                     document.NewPage();
            }
            document.Close();
            byte[] by = ms.ToArray();
             
             return by;
        }

         private static Image CreateBarcodeImage(string barcodeText)
        {
            Barcode39 code39 = new Barcode39();
            code39.BarHeight = 5;
            code39.Code = barcodeText;
             System.Drawing.Bitmap bm = new System.Drawing.Bitmap(code39.CreateDrawingImage(System.Drawing.Color.Black, System.Drawing.Color.White));
            MemoryStream ms = new MemoryStream();
             bm.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
            Image img = iTextSharp.text.Image.GetInstance(ms.ToArray());
             return img;
        }
    }
}

Let's walk through the above code. The very first block of code in the demo method just creates a DataTable on the fly for demo purposes. In real life, you would probably pass some sort of ID as a parameter to the method and use a DataAdapter to get your table of results out of your database. The next block of code sets up our Document object:

            Document document = new Document(PageSize.LETTER, 10, 10, 10, 10);
            MemoryStream ms = new MemoryStream();
            PdfWriter wr = PdfWriter.GetInstance(document, ms);
             document.Open();
            BaseFont bf = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, false);
            Font tbf = new Font(bf, 9, Font.NORMAL, Color.BLACK);

You can see I've created a font to use for the text. You can create as many fonts as you need for different types of text. For this contact list, I chose to use a series of Table objects, as it makes it easier to do repetitive operations in a loop. There are, however, other ways to do it. Next we get into the actual generation of the PDF:

             int ctr = 0;
            foreach (DataRow row in dt.Rows)
            {
                PdfPTable table = new PdfPTable(4);
                table.WidthPercentage = 100;
                table.SpacingBefore = 2;
                table.SpacingAfter = 2;

                float[] widths = new float[] { 1f, 1.5f, .75f, .75f };
                table.SetWidths(widths);
                PdfPCell cell = new PdfPCell(new Phrase("___________________________________________________________________________________"));
                cell.Colspan = 4;
                cell.Border = 0;
                cell.Padding = 1;
                cell.HorizontalAlignment = 0;
                table.AddCell(cell);// the horizontal line  

We're creating a PdfPtable with 4 columns. We set the width and some spacing, and then we set the relative width of each column with an array of floats. To create the first row, which will just display a line across the page,  I make a cell with a Colspan of 4, and add it to my table. Next I'm going to add the barcode:

                var img = CreateBarcodeImage(Convert.ToString(row["ID"]));
                PdfPCell cell2 = new PdfPCell(img);
                cell2.Border = 0;
                cell2.Padding = 1;
                table.AddCell(img);
                Phrase phrName = new Phrase((String)row["NameFirst"] + " " + (string)row["NameLast"], tbf);
                PdfPCell cell3 = new PdfPCell(phrName);
                cell3.Border = 0;
                cell3.Padding = 0;
                table.AddCell(cell3);

Making barcodes is a little complicated so I've abstracted it out into its own method:

private static Image CreateBarcodeImage(string barcodeText)
        {
            Barcode39 code39 = new Barcode39();
            code39.BarHeight = 5;
            code39.Code = barcodeText;
             System.Drawing.Bitmap bm = new System.Drawing.Bitmap(code39.CreateDrawingImage(System.Drawing.Color.Black, System.Drawing.Color.White));
            MemoryStream ms = new MemoryStream();
             bm.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
            Image img = iTextSharp.text.Image.GetInstance(ms.ToArray());
             return img;
        }

Once you've added enough cells to populate an entire row of columns (in this case, 4) the next cell added actually starts a new row automatically. The following block of code adds an entire row, with a first cell that is blank:

                 PdfPCell cellspc = new PdfPCell(new Phrase("    "));
                cellspc.Border = 0;
                cellspc.Padding = 0;
                table.AddCell(cellspc);

                string citystzip = (string)row["city"] + ", " + (string)row["state"] + " " + (string)row["zipcode"];
                PdfPCell cell10 = new PdfPCell(new Phrase(citystzip, tbf));
                cell10.Border = 0;
                cell10.Padding = 0;
                table.AddCell(cell10);

                PdfPCell cell11 = new PdfPCell(new Phrase("[ ] NO", tbf));
                cell11.Border = 0;
                cell11.Padding = 0;
                table.AddCell(cell11);

                PdfPCell cell12 = new PdfPCell(new Phrase("[ ] Deceased", tbf));
                cell12.Border = 0;
                cell12.Padding = 0;
                table.AddCell(cell12);

In the testing process, I discovered that I can comfortably fit 8 of these tables on one page, so I have the following code to do the pagination:

  if (ctr % 8 == 0)
    document.NewPage();

Finally, close the document and return the PDF as a byte array:

             document.Close();
            byte[] by = ms.ToArray();             
             return by;

The resulting PDF will look like this (showing only two rows):




You can download the complete Visual Studio 2010 Solution, which includes the iTextSharp assembly.

By Peter Bromberg   Popularity  (4025 Views)