Why iText?
Updated 2012-02-08 - Added a bullet regarding using iTextSharp with a medium trust shared web hosting provider in the notes section.
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 / Breaking Changes
- For some reason a lot of people using iText[Sharp] primarily want to use the library for HTML to PDF conversion. It also seems the percentage of .NET developers is higher. I completely agree with the comment by Mark Storer, an iText committer, at the bottom of that page. With that being said, the development team is shifting their their efforts from the HTMLWorker class (traditionally used to convert HTML to PDF) to XMLWorker, which was released on 2011-06-08. Here are some useful links:
- XMLWorker API
- XMLWorker Documentation - a really rough work in progress.
- XMLWorker Demo
- iTextSharp XMLWorker - it's a separate download
- iText 5.0.1.1, released on 2010-04-05, introduced Generics (System.Collections.Generic Namespace) in many classes. Prior versions used collections from the System.Collections Namespace.
- Due to a lazy, stupid question on the mailing list, the source code for all iTextSharp versions prior to 5.0 that fall under the GNU Lesser General Public License were removed on 2011-03-28 from the SourceForge source code / file download page. If you think that's a harsh statement, the tutorial (code) referenced by the OP was clearly dated as almost SIX YEARS OLD.
- iText 5.0.6, released on 2011-02-18, now supports the IDisposable interface for all classes that implement the IDocListener interfaceor inherit from the PdfStamper class. So if you prefer, creating a PDF is now a four-step process - just add a using statement and you can forget all those
Close()
calls. Another simple specific example using bothDocument
andPdfStamper
. - The
Table
andHeaderFooter
objects in the original code snippets (written sometime in 2007) are two of the many classes removed in iText 5.0.0, which was released on 2009-12-07. - For those still using an older version of iText[Sharp], a stand-alone example is included in the section below titled "Example for iTextSharp Versions Less Than 5.XX"; the F/OSS license was also changed from MPL/LGPL to AGPL starting with iText 5.0.0. Here is a mailing list thread that describes some of the reasons for the license change. But a word of advice - you're better off going with the newer 5.X.x branches.
Getting Started
In general creating a PDF with iText[Sharp] is a five-step process:
- Instantiate a Document object.
- Get an instance of the PdfWriter object.
- Open the Document instance.
- Add content to the Document instance.
- Close the document. As explained above you can omit step 5 from iTextSharp 5.0.6.
The following example shows how to:
- Create a centered, single-page document header. If you need to add page headers to all pages of your document see Adding PDF Page Headers, which shows the recommended method to add page headers using the PdfPageEventHelper class.
- Add a center-aligned image to the document.
- Add a center-aligned paragraph to the document.
- Add tabular formatted data to the document.
iTextSharp Versions 5 and Above
Creating our PDF going from step 1 through 4. Uncomment where specified (Document
using
statement) if using anything less than 5.0.6:/* * step 1 * * __ONLY__ if using version >= 5.0.6 * see commented section directly below * */ using (Document doc = new Document()) { /* * uncomment this line __AND__ comment out line above if you're * using version < 5.0.6 * * Document doc = new Document(); * */ // step 2 PdfWriter writer = PdfWriter.GetInstance(doc, Response.OutputStream); // step 3 doc.Open(); // step 4 /* * create document header; shows GMT time when PDF created. * HeaderFooter class removed in iText 5.0.0, so we instead write * content to an **absolute** position on the document */ Rectangle page = doc.PageSize; PdfPTable head = new PdfPTable(1); head.TotalWidth = page.Width; Phrase phrase = new Phrase( DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss") + " GMT", new Font(Font.FontFamily.COURIER, 8) ); 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 ); /* * add image to document */ Image gif = Image.GetInstance( Request.MapPath("~/kyouyuu/image/kuujinbo2.gif") ); gif.Alignment = Image.MIDDLE_ALIGN; // downsize the image by specified percentage gif.ScalePercent(50f); doc.Add(gif); /* * add tabular data */ // table heading Paragraph p = new Paragraph("US Presidents Born in " + _state); p.Alignment = 1; doc.Add(p); // table data, see code snippet following this one doc.Add( _stateTable() ); /* * step 5 is __REQUIRED__ if using version < 5.0.6; uncomment Close() * below and comment out the bracket below! * * doc.Close(); * */ }
Creating a simple table is easy; query the database (data access code omitted) and add each rowset to the table in the PDF:
// add a table to the PDF document private PdfPTable _stateTable() { string[] col = { "No.", "Name", "City" }; PdfPTable table = new PdfPTable(3); /* * default table width => 80% */ table.WidthPercentage = 100; // then set the column's __relative__ widths table.SetWidths(new Single[] {1, 5, 4}); /* * by default tables 'collapse' on surrounding elements, * so you need to explicitly add spacing */ 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; }
Example for iTextSharp Versions Less Than 5.XX
Here's a stand-alone working HTTP handler that works with 4.1.6.
<%@ WebHandler Language='C#' Class='itext' %> /* * example ONLY WORKS for iTextSharp < 5.0.0; * as of 2011-03-28 source code for older versions __NOT__ available */ using System; using System.Web; using iTextSharp.text; using iTextSharp.text.pdf; public class itext : IHttpHandler { // =========================================================================== public void ProcessRequest (HttpContext context) { HttpResponse Response = context.Response; Response.ContentType = "application/pdf"; Response.AppendHeader( "Content-Disposition", "attachment; filename=itext.pdf" ); // step 1 Document doc = new Document(); // step 2 PdfWriter writer = PdfWriter.GetInstance(doc, Response.OutputStream); /* * create document header; shows GMT time when PDF created. * set header [1] text [2] font style */ Phrase phrase = new Phrase( DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss") + " GMT", new Font(Font.COURIER, 8) ); HeaderFooter header = new HeaderFooter (phrase, false); // top & bottom borders on by default header.Border = Rectangle.NO_BORDER; // center header header.Alignment = 1; /* * HeaderFooter => add header __before__ opening document */ doc.Header = header; // step 3 doc.Open(); // step 4 /* * add image to document */ Image gif = Image.GetInstance( "http://kuujinbo.info/kyouyuu/image/kuujinbo2.gif" ); gif.Alignment = Image.MIDDLE_ALIGN; // downsize the image by specified percentage gif.ScalePercent(50f); doc.Add(gif); /* * add tabular data */ // table heading Paragraph p = new Paragraph("Table Heading"); p.Alignment = 1; doc.Add(p); // table 'data' Table table = new Table(3); table.BorderWidth = 1; table.BorderColor = new Color(0, 0, 255); table.Padding = 4; table.Width = 100; // set *column* widths float[] widths = {.3f, .5f, .4f}; table.Widths = widths; string[] col = {"COL 1", "COL 2", "COL 3"}; 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(); for (int i = 1; i < 5; ++i) { for (int j = 0; j < col.Length; ++j) { table.AddCell(string.Format( "Row {0}, Cell {1}", i, j + 1 )); } } doc.Add(table); // step 5 doc.Close(); } public bool IsReusable { get { return false; } } // =========================================================================== }
Notes
- If you don't own the book, see what some of the the differences between iText and iTextSharp. It will help when you look through the source code, since the API is only available in Java.
- Occasionally questions pop up on the mailing list or one of the many programming forums about problems with a corrupt PDF generated when working with a MemoryStream. It's usually a result of calling MemoryStream.GetBuffer(). See this mailing list postexplaining why you should be calling MemoryStream.ToArray() instead. In most cases you DO NOT need to use a
MemoryStream
to create the PDF! I've lost track of how many programming forum posts and web sites I've seen showing examples usingMemoryStream
. If you're a web developer, you have access to Response.OutputStream, so use it! And if you're a desktop application developer you can use any Stream of your choice. - If your web site is on a shared web hosting service and only allows Medium Trust, you need to download the source code and build it yourself.
Don't forget to set the correct Content-Type before you send the PDF stream if you're running a web application:
Response.ContentType = "application/pdf"; // [optional] Response.AddHeader( "Content-Disposition", "attachment; filename=itext.pdf" );