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:
And you must take into consideration that iText[Sharp] has never made HTML/XML to PDF conversion one of it's main goals or selling points. Whether you use HTMLWorker or XMLWorker, DO NOT EXPECT A FULL-BLOWN CONVERSION TOOL, YOU WILL BE DISSAPOINTED!
- 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 both Document
and PdfStamper
.
- The
Table
and HeaderFooter
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
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"
);