Add JavaScript to a PDF Document with iTextSharp

Originally posted June 8 2010

As you might have guessed from the title, this post is of the “get it done” variety.  So, the code may be a little rough.  Its the sort of code that works, but isn’t fully understood (by me at least).  I wasn’t able to find a clear example on the net, so I pieced together examples and guesses based on reading the code and interpreting method and class names.

Why guess?  Well, iTextSharp is a pretty robust open source project which is useful for creating and manipulating PDF documents.  The problem is, it doesn’t seem to have any useful documentation online.  It is open source, so you can read the code all day.  Also, there are some tutorials that you can download from the files page (in the examples folder).

The goal was to have a PDF document print automatically from a web page.  I decided to pass on coming up with a cross-browser (read: works in IE) method for automatically printing the document on the client, and instead decided to insert JavaScript into the generated PDF document that would cause it to print when opened.  This is what I came up with.

PdfReader reader = new PdfReader(inputStreamOrFile);
int pageCount = reader.NumberOfPages;
Rectangle pageSize = reader.GetPageSize(1);
// Setup writer
PdfDocument document = new PdfDocument(pageSize);
PdfWriter writer = PdfWriter.GetInstance(document, outputStreamOrFile);
document.Open();
// Copy each page
PdfContentByte content = writer.DirectContent;
for (int i = 0; i < pageCount; i++)
{
document.NewPage();
PdfImportedPage page = writer.GetImportedPage(reader, i + 1); // page numbers are one-based
content.AddTemplate(page, 0, 0); // x and y correspond to position on the page?
}
// Insert JavaScript to print the document after a fraction of a second (allow time to become visible).
string jsText = “var res = app.setTimeOut(‘var pp = this.getPrintParams();pp.interactive = pp.constants.interactionLevel.full;this.print(pp);’, 200);”;
//string jsTextNoWait = ”var pp = this.getPrintParams();pp.interactive = pp.constants.interactionLevel.full;this.print(pp);”;
PdfAction js = PdfAction.JavaScript(jsText, writer);
writer.AddJavaScript(js);

document.Close()

As for the JavaScript, the call to setTimeOut is there so that the PDF is rendered before the print dialog is shown.  Otherwise, the users will see the print dialog and a blank page, which may be confusing.  If the PDF is not visible anyway (as in my case) then you don’t really need the timeout.  The actual printing is based on the documentation of Acrobat JavaScript from Adobe’s website.  In this example, the iteration level is set to “full”, meaning that the user will get the print dialog and progress feedback.  You can also use “automatic” (no dialog, includes progress) and “silent” (no dialog or progress).

PDF Embed Weirdness

Originally posted April 5 2010

The other day I was working on a web page where the user does some stuff and then as the result a nice, shiny PDF is embedded in the page. I noticed that in Internet Explorer (I was using IE8) the embedded region showed up as a blank rectangle with a little icon in the upper left-hand corner. Weird…

One of my co-workers suggested that I try embedding a static PDF file. In my case the source URL was an aspx page that dynamically renders the PDF. But that can’t possibly matter, right? I mean, as long as the content type is correct and the file is intact. I guess it does.

I won’t bore you with the details, but I determined through trial and error that the following conditions had to be met for the embedded PDF to display in IE8:

1) The “type” attribute must be specified as “application/pdf”, regardless of the fact that the external resource has the correct content type header. Because of my own ignorance I freely accept that there is probably a good reason for this. Besides, its good practice anyway – especially in my case (“what does this Page.aspx render as???”).

2) The URL must include “pdf” or “.pdf” (not sure if the “.” is necessary), even if on the query string! Really? I didn’t believe it myself, but I tested a gratuitous number of times and eventually disbelief gave way to sheer exhaustion.

3) Embed tag must be injected into the page with all attribute values at once (using jQuery) rather than injecting the tag and then setting attribute values (like type and src). This may be a jQuery issue, but its worth mentioning anyway.

So, the moral of the story is…

If it doesn’t work then first reduce the problem to its simplest form.