Why iText?

How many times have you been asked to generate a report in an open file format such as PDF? iTextSharp a free C# PDF library ported from the Java-PDF Library iText, gives you a nice option.

IMPORTANT

Getting Started

The following example shows how to:

  1. Create a centered document header.
  2. Add a center-aligned image to the document.
  3. Add a center-aligned paragraph to the document.
  4. Add tabular formatted data to the document.

Steps 1 - 3

// create PDF and send to client
private void _write_stream() {
  Document doc = new Document();
  try {
/*
// DON'T DO THIS
  using ( MemoryStream ms = new MemoryStream() ) {
    // the object required to write to a (output) Stream
    PdfWriter.GetInstance(doc, ms);
*/

// INSTEAD DO THIS TO SAVE IN-MEMORY COPY
    PdfWriter writer = PdfWriter.GetInstance(doc, Response.OutputStream);
    Phrase phrase = new Phrase(
      DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss") + " GMT",
      new Font(Font.COURIER, 8)
    );
    doc.Open();
    // create document's header; shows GMT time when PDF created.
    // HeaderFooter class removed in iText 5.0.0;, we must write 
    // content to an **absolute** position on the document
    Rectangle page = doc.PageSize;
    PdfPTable head = new PdfPTable(1);
    head.TotalWidth = page.Width;
    PdfPCell c = new PdfPCell(phrase);
    c.Border = Rectangle.NO_BORDER;
    c.VerticalAlignment = Element.ALIGN_TOP;
    c.HorizontalAlignment = Element.ALIGN_CENTER;
    head.AddCell(c);
    head.WriteSelectedRows(
      // first/last row; -1 writes all rows
      0, -1,
      // left offset
      0,
      // ** bottom** yPos of the table
      page.Height - doc.TopMargin + head.TotalHeight + 20,
      writer.DirectContent 
    );
/*
* 
* iText versions older than 5.0.0
* 
    // create document's header; shows GMT time when PDF created.
    // set header [1] text [2] font style
    HeaderFooter  header = new HeaderFooter (phrase, false);
    // top & bottom borders on by default 
    header.Border = Rectangle.NO_BORDER;
    // center header
    header.Alignment = 1;
    // add header *before* opening document
    doc.Header = header;
    doc.Open();
*/

    // add image to document
    Image gif = Image.GetInstance(
      Request.MapPath("~/image/kuujinbo2.gif")
    );
    gif.Alignment = Image.MIDDLE_ALIGN;
    gif.ScalePercent(50f); // change it's size
    doc.Add(gif);

    // report "title"
    Paragraph p = new Paragraph("US Presidents Born in " + _state);
    p.Alignment = 1;
    doc.Add(p);

    // add tabular data
    doc.Add( _state_table() );
    // PRE iText 5.0.0
    // doc.Add( _state_table_pre5() );
/*
* AGAIN DON'T DO THIS
    Response.BinaryWrite( ms.ToArray() );
*/
  }
  catch   { throw; }
  finally { if (doc != null) doc.Close(); }
}

Creating a simple table is easy; query the database (database code omitted) and add each rowset to the table in the PDF:

Step 4

iText 5.0.0 and above

// add a table to the PDF document
private PdfPTable _state_table() {
  string[] col = { "No.", "Name", "City" };
  PdfPTable table = new PdfPTable(3);
  table.WidthPercentage = 100;
  table.SetWidths(new Single[] {1, 5, 4});
  table.SpacingBefore = 10;

  for (int i = 0; i < col.Length; ++i) {
    PdfPCell cell = new PdfPCell(new Phrase(col[i]));
    cell.BackgroundColor = new BaseColor(204, 204, 204);
    table.AddCell(cell);
  }

// !! database code omitted !!
// r.Read is the DbDataReader for whatever flavor 
// of database you're connecting to; we're iterating
// over the results returned from the database and 
// adding rows to the table in the PDF 
        while (r.Read()) {
          table.AddCell(r["id"].ToString());
          table.AddCell(r["name"].ToString());
          table.AddCell(r["city"].ToString());
        }
  }
  return table;
}

iText versions older than 5.0.0

// add a table to the PDF document
private Table _state_table() {
  // the column headings
  string[] col = {"No.", "Name", "City"};
  Table table = new Table(3);
  // set table style properties
  table.BorderWidth = 1;
  table.BorderColor = new Color(0, 0, 255);
  table.Padding = 4;
  table.Width = 100;

  // set *column* widths
  float[] widths = {.1f, .5f, .4f};
  table.Widths = widths;

  // create the *table* header row
  for (int i = 0; i < col.Length; ++i) {
    Cell cell = new Cell(col[i]);
    cell.Header = true;
    cell.BackgroundColor = new Color(204, 204, 204);
    table.AddCell(cell);
  }
  table.EndHeaders();

  // !! database code omitted !!
  // r.Read is the DbDataReader for whatever flavor 
  // of database you're connecting to; we're iterating
  // over the results returned from the database and 
  // adding rows to the table in the PDF 
        while (r.Read()) {
          table.AddCell( r["id"].ToString() );
          table.AddCell( r["name"].ToString() );
          table.AddCell( r["city"].ToString() );
        }

  return table;
}

Notes

  • The Java library uses getXXX and setXXX methods to do a lot of things, while the .NET port uses properties.
  • The .NET documentation is a little lacking. For example, both the Java API and the tutorial specify Image.MIDDLE to align an image in the middle of the document - I had to find out the hard way that you need Image.MIDDLE_ALIGN. So be prepared to dig in the package's source code!
  • Didn't really want to use ms.ToArray(), but couldn't figure out how to read/send the stream in chunks. (MemoryStream.CanRead returns false) 2007-06-05 update: Duh! After browsing through the mailing list I figured out how to save in-memory copying of the PDF: (1) replace the MemoryStream parameter to PdfWriter.GetInstance() with Response.OutputStream (second parameter), and (2) disable buffering to the client: Response.BufferOutput = false;.
And don't forget to set the correct Content-Type before you write the PDF to the client:
Response.ContentType = "application/pdf";
Response.AddHeader(
  "Content-Disposition",
  "attachment; filename=itext.pdf"
);

More kuujinbo.info iText examples

iText References