Click here to Skip to main content
Click here to Skip to main content

Creating PDF documents with iTextSharp

, 2 Nov 2011 CPOL
Rate this:
Please Sign up or sign in to vote.
Creating PDF documents with iTextSharp using a combination of images and text.

Editorial Note

This article appears in the Third Party Product Reviews section. Articles in this section are for the members only and must not be used by tool vendors to promote or advertise products in any way, shape or form. Please report any spam or advertising.

Introduction

This article is about using iText to generate PDF files using a combination of images and dynamic text written on select locations on the image. The example project uses an ASP.NET MVC3 application to demonstrate the code but it should not be difficult to adapt it to your own needs.

Background

Me and some friends have been running a hobby web-site called malleus.dk dedicated to two role-playing games called Warhammer Fantasy and Dark Heresy.

One of the applications on our site is a "character generator" where users can build, configure, and maintain their role-playing characters. We wanted to expand this tool with a print functionality allowing our users to have their characters printed to a nice looking character sheet.

We decided that we really needed to generate a PDF document. PDF documents are supported in all browsers and seems to be the de-facto standard for documents on the web. There are a lot of PDF components available on the net, but we quickly settled on iText as it is a very mature product.

iText comes with a free option under the GNU Affero Public License, or with a commercial option which gives you more freedom. I encourage you to check out the details at http://itextpdf.com.

Using the example solution

The example solution contains two projects - a Class Library and an ASP.NET MVC application. iText is used from the Class Library, and the web application is used for testing the Class Library.

The example creates a "diploma" for a bicycle race. You can enter name, date, the name of the race, and the distance. The web application will produce a diploma with the entered text on top.

The basic flow of the example application is illustrated with images in figure 1, 2, and 3:

The background image

Figure 1 - The background image

Entering data in example app

Figure 2 - Entering data in example app

Clicking "Generate" will create a new PDF document:

The resulting diploma

s
Figure 3 - The resulting diploma

From here on, it is only a matter of adding more artwork, tweaking texts, fonts, etc.

Even though the diploma application is very basic, it contains all the programmatic elements required for producing output that looks like figure 4. The artistic skill that goes into images and layout is a job for a designer.

Character sheet in PDF generated using iText

Figure 4 - Character sheet in PDF generated using iText

Installing and setting up

Go to http://itextpdf.com/download.php and click "Download iTextSharp". In your Visual Studio project, you need to reference the itextsharp.dll that you just downloaded.

Document generation strategy

When you open up iText and begin examining the API, you will notice that it is capable of writing text, drawing figures, inserting images, creating PDF forms, etc.. For our task, we decided to use a combination of image fragments and text. The bottom layer will contain all the image fragments and the top layer will contain the text.

Creating a PDF document

When you create PDF documents in iText, the top-level abstraction is the Document class. It provides various document level information such as title, page count, etc.:

public void Create (Stream output) {
  Document document = new Document();
  PdfWriter writer = PdfWriter.GetInstance(document, output);
  document.Open();

The output stream is just a MemoryStream which is returned as a FileContentResult:

[HttpPost] 
public FileContentResult Generate(GenerateModel m) {
    DiplomaPrinter printer = 
      new DiplomaPrinter(m.Name, m.Distance, m.Date, m.RaceName, m.ShowRulers);
    MemoryStream memoryStream = new MemoryStream();
    printer.Create(memoryStream);

    return File(memoryStream.GetBuffer(), "application/pdf", "diploma.pdf");
}

When this controller action is invoked, it will send the contents of the MemoryStream back to the client as a PDF file called "diploma.pdf".

To actually fill the document with content, you need to learn to use the PdfWriter, PdfReader, and PdfTemplate classes.

Bottom layer

The bottom layer of the page is filled with other PDF fragments and images. Figure 2 contains our background image. To load these elements into the document, you do the following:

  1. Load the PDF fragment using a PdfReader.
  2. Use the reader to create a PdfTemplate instance.
  3. Add the PdfTemplate to your current Document instance.
PdfReader readerBicycle = new PdfReader(Resources.GetBicycle());
PdfTemplate background = writer.GetImportedPage(readerBicycle, 1);

Create a new page in the document and add the PdfTemplate instance to it:

document.NewPage();
PdfContentByte pcb = writer.DirectContentUnder;
pcb.AddTemplate(background, 0, 0);

Resource.GetBicycle() simply returns a Stream instance to a resource embedded within the assembly. The call to document.NewPage() generates a new page in the Document instance and the writer.DirectContentUnder property returns a PdfContentByte instance for the bottom layer of this new page. The pcb.AddTemplate() invocation adds the loaded PDF fragment to the document and positions it on the bottom left corner - coordinates x = 0 and y = 0.

At first it seems odd that you have to use the PdfWriter instance to transform the contents of the PdfReader into a PdfTemplate. As Bruno Lowagie - the creator of iText - explained to me, this is done to ensure that shared objects are reused. For instance, if you embed your own fonts in the document, the best option is to reuse this font whenever you write some text.

For more specific details, I encourage you to get a hold of the book "iText in Action - 2nd edition".

Top layer

The top layer is where I put the text. As with everything else in iText, you have several options. You can add entire paragraph objects or print text at specific points. Since I need to print on top of an image/PDF fragment, I went with the last option.

PdfContentByte pcb = writer.DirectContent;
pcb.BeginText();
SetFont36();
PrintTextCentered(_raceName, 280, 680);
PrintTextCentered(_name, 280, 190);

SetFont18();
PrintTextCentered(_date, 280, 640);
PrintTextCentered("has completed a distance of " + _distance, 280, 160);

_pcb.EndText();
writer.Flush();

The numbers in this code fragment represent a position in a coordinate system.

Setting the font and size:

private static readonly BaseFont font = 
    BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, false);

private void SetFont36() {
    _pcb.SetFontAndSize(font, 36);
}

Invoking this method will set the font to Helvetica with size 36. This will affect the invocations to the following method:

private void PrintTextCentered(string text, int x, int y) {
    _pcb.ShowTextAligned(PdfContentByte.ALIGN_CENTER, text, x, y, 0);
}

The _name, _distance etc. fields are injected into the DiplomaPrinter class via the constructor.

Closing the document

To end the document, you should flush your writer and call Close on the document:

writer.Flush();
document.Close();

This has the effect of pushing the PDF document down to the output stream that you used to create the document with in the first place.

Tricks

When generating documents this way, you often need to adjust the position of text and images. To help with this, I created two methods for adding a ruler to the generated PDF document. If you check the "add rulers" box in the example application, you should see something like the following:

Diploma with rulers

Figure 5 - Diploma with rulers

Having these rulers makes it much easier to find the positions of text and images.

You can also play around with the code-page being used by iText when generating text. This is done by changing the value of the encoding parameter of the BaseFont.CreateFont() method. The example uses the value "Cp1252" which is for Western Europe. Reading the source code for iText, I can see that it also supports the values "Cp1250" (Central- and Eastern Europe) and "Cp1257" (the three Baltic states) but I have yet to play around with these.

Conclusion

iText is a mature piece of software with tons of possibilities. I have only scratched the surface of what is possible. A quick scan of the API reveals that you can do PDF forms, drawing, encryption, etc. I once tried to read the PDF specification and found that it is one complex beast. I very much prefer delegating the work to an API such as iText.

History

  • 1 November 2011 - First edition.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Thomas Michael Koch
Software Developer (Senior)
Denmark Denmark
No Biography provided

Comments and Discussions

 
QuestionQuality is lower in production (older operating system) Pinmemberksyinc245120-Feb-14 9:35 
GeneralMy vote of 5 PinprofessionalRenju Vinod28-Oct-13 18:54 
NewsCode breaks on 5.4.2 Pinmemberalpinescrambler22-Jul-13 7:31 
GeneralMy vote of 5 PinmemberEric Willingham27-Feb-13 3:37 
QuestionAdding fields with custom font PinmemberMember 40173815-Feb-13 23:05 
QuestionHow to show special characters č or ć in pdf PinmemberAlmirM26-Nov-12 9:57 
QuestionHow to do the same with a web form Pinmemberameshlalvr1-Jul-12 21:53 
AnswerRe: How to do the same with a web form Pinmemberameshlalvr2-Jul-12 22:15 
GeneralRe: How to do the same with a web form Pinmemberameshlalvr2-Jul-12 22:59 
GeneralRe: How to do the same with a web form PinmemberThomas Michael Koch3-Jul-12 10:15 
GeneralRe: How to do the same with a web form Pinmemberameshlalvr5-Jul-12 0:41 
QuestionCan you point me to reference materials to help me incorporate the solution into an MFC application? Pinmemberconacher1-Dec-11 10:35 
AnswerRe: Can you point me to reference materials to help me incorporate the solution into an MFC application? PinmemberThomas Michael Koch1-Dec-11 14:23 
GeneralRe: Can you point me to reference materials to help me incorporate the solution into an MFC application? PinmemberMember 345539813-Jan-12 12:40 
Thanks Thomas.
I have been able to create the iTextSharp Wrapper.
Just having a bit of trouble with some of my form fields.
Some are populated fine, and then others fail.
I don't know why yet, as iTextSharp returns a bool true/false for setField, but when it returns false,
I don't get any hint as to what was wrong with the field name.
I know the first thought is that the field name is in error, but I have gone back and checked by creating an FDF file, and using the same field name, everything is fine.
QuestionWebform PinmemberKentACar8-Nov-11 4:53 
AnswerRe: Webform PinmemberThomas Michael Koch8-Nov-11 10:12 
GeneralRe: Webform PinmemberKentACar8-Nov-11 12:56 
GeneralMy vote of 5 Pinmemberblowagie5-Nov-11 6:36 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141223.1 | Last Updated 2 Nov 2011
Article Copyright 2011 by Thomas Michael Koch
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid