RSS Feed Feed your read!

Bookmark and Share







Tag Cloud

ASP.NET Generic, Best Practices, Business Intelligence, Freeware Releases, InfoPath, Infrastructure, jQuery, Lunch & Learn Events, Project Server, Random, Reporting Services, Search, SharePoint Administration, SharePoint Business Analysis and Project Management, SharePoint Development, Silverlight, Social Networking, Speaking Events, White Paper Releases, Workflow Foundation,

Archives

June 2007 (3)
August 2007 (1)
November 2007 (2)
February 2008 (2)
April 2008 (5)
May 2008 (7)
June 2008 (8)
July 2008 (7)
August 2008 (3)
September 2008 (7)
October 2008 (1)
November 2008 (3)
December 2008 (3)
January 2009 (7)
February 2009 (5)
March 2009 (10)
April 2009 (2)
May 2009 (6)
June 2009 (3)
July 2009 (4)
August 2009 (6)
September 2009 (3)
October 2009 (9)
November 2009 (10)
December 2009 (1)
January 2010 (1)
February 2010 (3)
March 2010 (6)
April 2010 (2)
May 2010 (3)
June 2010 (4)
July 2010 (3)

Programmatically Convert an InfoPath Form into a PDF 

Tags: InfoPath

This morning I set out on a journey to convert an InfoPath form into a PDF document programmatically. The journey came about in a Visual Studio workflow, because after a user submits the associated InfoPath form, the workflow was to take that form, convert it to a PDF, and thereafter archive the PDF into a separate site collection. This turned out to be a neat little business process when all was said and done.

 

As far as generating the PDF goes, I decided to elicit a little help from a third party. I ran into Winnovative PDF, and they have a tool that takes HTML and converts that HTML into a PDF. While this isn't the silver bullet I would have hope it would have been (take the form itself, rather than HTML), I knew it wasn't that hard to convert an InfoPath form into HTML. Then the tool can do the dirty work for me to build the PDF.

 

Convert an InfoPath form to HTML

 

The basic steps are to grab the SPFile object that is the InfoPath form you want to convert to a PDF. Then, open a Stream that has the XSL that you can use to transform the form data (XML) into HTML. You can get the XSL from an InfoPath form out of the XSN file itself. The XSN file that is an InfoPath form is actually just a CAB that has many kinds of files in it, one of which is our XSL file. You'll see one XSL file for every view you've built in the InfoPath form. This is the XSL file you want:

 

After you have the XSL (one file for each view in the InfoPath form) in your Visual Studio project, use the following code to transform the form XML data into HTML:

 

 

string html = "";
using (SPSite site = new SPSite("http://contoso.com/acceptance"))
{
    using (SPWeb web = site.RootWeb)
    {
        // grab the folder that contains the form
        SPFolder folder = web.Folders["InfoPath Forms"];

        // grab the InfoPath form itself
        SPFile file = folder.Files["SomeForm.xml"];

        XslCompiledTransform transform = new XslCompiledTransform();

        // embedded rource file name (this is your XSL document
        // you pulled out of the XSN/Cab).
        string resourceName = @"AssemblyName.SomeForm.xsl";

        // Load resource out of dll and into a stream
        using (Stream res =
            Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
        {
            // load stylesheet into the transformer
            using (XmlTextReader stylesheet = new XmlTextReader(res))
            {
                transform.Load(stylesheet);
            }
        }

        StringWriter sWriter = new StringWriter();
        HtmlTextWriter writer = new HtmlTextWriter(sWriter);

        // read the contents (XML) out of the InfoPath form
        using (XmlReader reader = new XmlTextReader(file.OpenBinaryStream()))
        {
            XmlTextWriter results = new XmlTextWriter(writer.InnerWriter);

            // Perform the transformation
            transform.Transform(reader, results);
            reader.Close();
        }

         // the transformation will load the resulting HTML into a string
        html = sWriter.ToString();
    }
}

 

Convert HTML into a PDF

 

For this second stage in the process, I used a tool from Winnovative to do the heavy lifting. It's a great tool that integrates into Visual Studio and comes in inexpensive at $350. Their API is rather intuitive, as you can see:

 

 

PdfConverter pdfConverter = new PdfConverter();

// set the license key (this is the public trialwear license
pdfConverter.LicenseKey = "Q2hzY3Jjc2N3bXNjcHJtcnFtenp6eg==";

// set the converter options
pdfConverter.PdfDocumentOptions.PdfPageSize = PdfPageSize.A4;
pdfConverter.PdfDocumentOptions.PdfCompressionLevel = PdfCompressionLevel.Normal;
pdfConverter.PdfDocumentOptions.PdfPageOrientation = PDFPageOrientation.Portrait;
pdfConverter.PdfDocumentOptions.ShowHeader = false;
pdfConverter.PdfDocumentOptions.ShowFooter = false;

// set to generate selectable pdf or a pdf with embedded image
pdfConverter.PdfDocumentOptions.GenerateSelectablePdf = true;

// Performs the conversion and get the pdf document bytes
byte[] pdfBytes = null;
pdfBytes = pdfConverter.GetPdfBytesFromHtmlString(html);

 

 

At the end of this code block, you're left with a byte array. This byte array contains all the bytes that make up the PDF file. Let's now take those bytes and re-write them back into SharePoint, but this time as a PDF!

 

 

// open SPWeb/SPFolder that will be taking the PDF
SPFolder archive = someSPWeb.Folders["Archived Forms"];

// grab the SPFile that is the InfoPath form, and use the
// name for the new PDF's name, but change the extension
string filename = file.Name.Replace(".xml", ".pdf");

// Add the file to the Files collection and commit to database
SPFile archivedFile = archive.Files.Add(archive.Url + "/" +
filename, pdfBytes, true);
archive.Update();

 

 

SWEET! Now we have an archived InfoPath for that's in a PDF format! Optionally, you could write the file to the file system:

 

 

string filename = file.Name.Replace(".xml", ".pdf");

// Outputs the document to the current web page
FileStream s = new FileStream("c:\\somefolder\\onserver\\harddrive\\" + filename, FileMode.Create);
    s.Write(pdfBytes, 0, pdfBytes.Length);

 

 

What CAN'T you do with code? And ain't workflows sweet? I'm such a geek (and a pseudo hick) J

 

Phil

 
Posted by Phillip S. Wicklund on 6-Mar-09
0  Comment  |  Trackback Url  | 0  Link to this post | Bookmark this post with:        
 
Failed to render control: Value does not fall within the expected range.

Comments

Bookmark and Share

Note: Facebook no longer sends notifications for comments, so it may be a number of days before I see your post. For urgent matters, click "Contact Me" on the top nav. More info: Click Here.