Monday, April 29, 2013

Printing a PDF from a web page

The requirement in this case is to print a PDF document, but not allow the user to manipulate the PDF in any other way. The user should see the Print Dialog box and be able to manipulate the settings. This requirement was born out of an auditing policy where the document is audited differently for printing or viewing the PDF. I found lots of web discussion about printing a pop-up window from the parent window, or trying to print the contents of an IFrame, but none of it worked for me. I was hit with security errors from IE about cross-domain issues, even though my pages were in the same domain, or just got a blank page. So to get a working solution, I had to step out of the web page.

The tool that really allowed me to do this is iTextSharp, a C# implementation of the iText Open Source Java library for manipulating PDF files, and the fact that you can use JavaScript within a PDF file. I used an ASPX page which manipulates and streams the PDF file into a zero-height, zero-width IFrame to keep the user from manipulating the PDF in any way (I realize tech-savvy users could still get the PDF). I embedded the JavaScript into the PDF, where it runs once the document is loaded and pops up the Print dialog from Adobe Reader (not the browser).

The JavaScript for printing a PDF is not so complex, I embedded it into a function:
protected string GetAutoPrintJs()
{
    var script = new StringBuilder();
    script.Append("var pp = getPrintParams();");
    script.Append("pp.interactive= pp.constants.interactionLevel.full;");
    script.Append("print(pp);"); return script.ToString();
}

In the code-behind for the ASPX page that will stream the PDF and place the script inside the PDF file, I built this function:
protected void StreamPdf(Stream pdfSource)
{
    var outputStream = new MemoryStream();
    var pdfReader = new PdfReader(pdfSource);
    var pdfStamper = new PdfStamper(pdfReader, outputStream);
    //Add the auto-print javascript
    var writer = pdfStamper.Writer;
    writer.AddJavaScript(GetAutoPrintJs());
    pdfStamper.Close();
    var content = outputStream.ToArray();
    outputStream.Close();
    Response.ContentType = "application/pdf";
    Response.BinaryWrite(content);
    Response.End();
    outputStream.Close();
    outputStream.Dispose();
}

The PDFReader and PDFStamper classes are members of the iTextSharp library. I used the classes together to get the stream for output and also access the PDFWriter object that allowed me to add the JavaScript.

No comments:

Post a Comment