John Chapman

[SharePoint 2010] Fill Out and Flatten PDF Forms with iTextSharp

Share on TwitterShare on LinkedInShare on TumblrSubmit to StumbleUponSave on DeliciousDigg ThisSubmit to reddit

In a recent project I used this solution to take fillable PDF forms, fill them out based on user input, flatten the PDF document and save it back to SharePoint. I can think of a number of uses for this type of solution: filling out contracts, filling out medical or other business forms, or just about any standard document that requires dynamic data inputted. This guide shows the fundamentals for accomplishing this, there are countless ways this could be modified to suit specific requirements.

Prerequisites

  1. A development environment with SharePoint 2010 and Visual Studio 2010 installed and configured
  2. A blank site on the SharePoint environment to work with
  3. A fillable PDF form (at least one), for this example I am using a sample Direct Deposit form from Microsoft Word that I converted to a PDF form. You can download the form here.
  4. iTextSharp (which can be downloaded here)

Guide

  1. Identify the names of the form fields that will be filled out by the application. (You can do this in Adobe Acrobat while editing the form). The field for our sample form are:

    • “Name of Financial Institution”
    • “Routing Number”
    • “Account Number”
    • “Checking”
    • “Savings”
  2. In your SharePoint site, create two Document Libraries named “Form Templates” and “Completed Forms”. (In a more complete solution, you might create content types and list definitions for these. For simplicity, we are just creating them on the site manually.)

  3. Upload your PDF form template (i.e. the Sample Form) to the “Form Templates” Document Library.

  4. Start Visual Studio 2010 and create a New Project. Select Visual Web Part for the template (Visual C# > SharePoint > 2010).

  5. Provide a Solution Name; for this guide we are using “PDFFormExample”. Select OK.

  6. Provide the local SharePoint site URL you will be testing with (on my machine I am using “http://localhost:8080/sites/pdfforms/”).

  7. Select Finish.

  8. In the Solution Explorer, right-click References > Add Reference. Browse to and add the iTextSharp DLL referece.

  9. In the “VisualWebPart1UserControl.ascx” user control, add the ASP.NET controls to gather the form information from the user. Here is my completed control:

    			<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
    			<%@ Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
    			<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
    			<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
    			<%@ Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
    			<%@ Import Namespace="Microsoft.SharePoint" %>
    			<%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
    			<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="VisualWebPart1UserControl.ascx.cs" Inherits="PDFFormExample.VisualWebPart1.VisualWebPart1UserControl" %>
    
    			<p>Form Template: <br/>
    				<asp:DropDownList ID="ddlTemplate" runat="server"></asp:DropDownList>
    			</p>
    
    			<p>Financial Institution: <br />
    				<asp:TextBox ID="txtFinancialInstitution" runat="server"></asp:TextBox>
    			</p>
    
    			<p>Routing Number: <br />
    				<asp:TextBox ID="txtRoutingNumber" runat="server"></asp:TextBox>
    			</p>
    
    			<p>Account Number: <br />
    				<asp:TextBox ID="txtAccountNumber" runat="server"></asp:TextBox>
    			</p>
    
    			<p>
    				<asp:CheckBox ID="chkChecking" runat="server" /> Checking <br/>
    				<asp:CheckBox ID="chkSavings" runat="server" /> Savings
    			</p>
    
    			<p>
    				<asp:Button ID="btnSubmit" runat="server" Text="Submit" />
    				<asp:Label ID="lblOutput" runat="server"></asp:Label>
    			</p>
    		
  10. Open the “VisualWebPart1UserControl.ascx.cs” code behind file (you will need to expand VisualWebPart1 in the Solution Explorer).

  11. Add an event handler for the “Click” action on the button we added to the user control:

    			using System;
    			using System.Web.UI;
    			using System.Web.UI.WebControls;
    			using System.Web.UI.WebControls.WebParts;
    
    			namespace PDFFormExample.VisualWebPart1
    			{
    				public partial class VisualWebPart1UserControl : UserControl
    				{
    					protected void Page_Load(object sender, EventArgs e)
    					{
    						btnSubmit.Click += new EventHandler(btnSubmit_Click);
    					}
    
    					void btnSubmit_Click(object sender, EventArgs e)
    					{
    
    					}
    				}
    			}
    		
  12. Add Microsoft.SharePoint, System.IO, iTextSharp.text.pdf, and iTextSharp.text to the using list:

    			using System;
    			using System.Web.UI;
    			using System.Web.UI.WebControls;
    			using System.Web.UI.WebControls.WebParts;
    			using Microsoft.SharePoint;
    			using iTextSharp.text;
    			using iTextSharp.text.pdf;
    			using System.IO;
    		
  13. Next, use the following code in the Page_Load function to query the form templates to populate the drop down list:

    			protected void Page_Load(object sender, EventArgs e)
    			{
    				btnSubmit.Click += new EventHandler(btnSubmit_Click);
    
    				if(!IsPostBack)
    				{
    					// Clear any items that exist in the drop down list
    					ddlTemplate.Items.Clear();
    
    					// Get the collection of list items in the Form
    					// Templates document library
    					SPListItemCollection formTemplates =
    						SPContext.Current.Web.Lists["Form Templates"].Items;
    
    					// For each list item in the collection, add the item to
    					// drop down list
    					foreach (SPListItem template in formTemplates)
    					{
    						// Get file name and the list item ID
    						string title = template.File.Name;
    						string id = template["ID"].ToString();
    
    						// Add new item to the drop down list
    						ddlTemplate.Items.Add(
    							new System.Web.UI.WebControls.ListItem(title, id));
    					}
    				}
    			}
    		
  14. Add the following code to the btnSubmit_Click function. Details on each step are in the code comments:

    			// Get the selected template ID
                int templateId = int.Parse(ddlTemplate.SelectedValue);
    
                // Get the template file from the document library
                SPFile template =
                    SPContext.Current.Web.Lists["Form Templates"].GetItemById(templateId).File;
    
                // Initialize a new iText document and specify the page size
                Document document = new Document(PageSize.LETTER);
    
                // Initialize a stream to process the new document
                MemoryStream stream = new MemoryStream();
    
                // Initialize a new iText reader to open the PDF form
                PdfReader reader = new PdfReader(template.OpenBinaryStream());
    
                // Initialize a new iText stamper to fill out the PDF form
                PdfStamper pdf = new PdfStamper(reader, stream);
    
                // Grab the form fields and set their values from the user controls
                AcroFields fields = pdf.AcroFields;
                fields.SetField("Name of Financial Institution", txtFinancialInstitution.Text);
                fields.SetField("Routing Number", txtRoutingNumber.Text);
                fields.SetField("Account Number", txtAccountNumber.Text);
                if (chkChecking.Checked)
                    fields.SetField("Checking", "X");
                if (chkSavings.Checked)
                    fields.SetField("Savings", "X");
    
                // Flatten and close the new PDF
                pdf.FormFlattening = true;
                pdf.Close();
    
                // Create a unique file name
                string fileName =
                    Guid.NewGuid() + "_" + txtAccountNumber.Text + ".pdf";
    
                // Upload the file to the Complete Forms library
                SPContext.Current.Web.Folders["Completed Forms"].Files.Add(fileName, stream.ToArray());
    
                lblOutput.Text = "Form successfully completed " + DateTime.Now;
    		
  15. Your completed code should look like:

    			using System;
    			using System.Web.UI;
    			using System.Web.UI.WebControls.WebParts;
    			using Microsoft.SharePoint;
    			using iTextSharp.text;
    			using iTextSharp.text.pdf;
    			using System.IO;
    
    			namespace PDFFormExample.VisualWebPart1
    			{
    				public partial class VisualWebPart1UserControl : UserControl
    				{
    					protected void Page_Load(object sender, EventArgs e)
    					{
    						btnSubmit.Click += new EventHandler(btnSubmit_Click);
    
    						if(!IsPostBack)
    						{
    							// Clear any items that exist in the drop down list
    							ddlTemplate.Items.Clear();
    
    							// Get the collection of list items in the Form
    							// Templates document library
    							SPListItemCollection formTemplates =
    								SPContext.Current.Web.Lists["Form Templates"].Items;
    
    							// For each list item in the collection, add the item to
    							// drop down list
    							foreach (SPListItem template in formTemplates)
    							{
    								// Get file name and the list item ID
    								string title = template["Name"].ToString();
    								string id = template["ID"].ToString();
    
    								// Add new item to the drop down list
    								ddlTemplate.Items.Add(
    									new System.Web.UI.WebControls.ListItem(title, id));
    							}
    						}
    					}
    
    					void btnSubmit_Click(object sender, EventArgs e)
    					{
    						// Get the selected template ID
    						int templateId = int.Parse(ddlTemplate.SelectedValue);
    
    						// Get the template file from the document library
    						SPFile template =
    							SPContext.Current.Web.Lists["Form Templates"].GetItemById(templateId).File;
    
    						// Initialize a new iText document and specify the page size
    						Document document = new Document(PageSize.LETTER);
    
    						// Initialize a stream to process the new document
    						MemoryStream stream = new MemoryStream();
    
    						// Initialize a new iText reader to open the PDF form
    						PdfReader reader = new PdfReader(template.OpenBinaryStream());
    
    						// Initialize a new iText stamper to fill out the PDF form
    						PdfStamper pdf = new PdfStamper(reader, stream);
    
    						// Grab the form fields and set their values from the user controls
    						AcroFields fields = pdf.AcroFields;
    						fields.SetField("Name of Financial Institution", txtFinancialInstitution.Text);
    						fields.SetField("Routing Number", txtRoutingNumber.Text);
    						fields.SetField("Account Number", txtAccountNumber.Text);
    						if (chkChecking.Checked)
    							fields.SetField("Checking", "X");
    						if (chkSavings.Checked)
    							fields.SetField("Savings", "X");
    
    						// Flatten and close the new PDF
    						pdf.FormFlattening = true;
    						pdf.Close();
    
    						// Create a unique file name
    						string fileName =
    							Guid.NewGuid() + "_" + txtAccountNumber.Text + ".pdf";
    
    						// Upload the file to the Complete Forms library
    						SPContext.Current.Web.Folders["Completed Forms"].Files.Add(fileName, stream.ToArray());
    
    						lblOutput.Text = "Form successfully completed " + DateTime.Now;
    					}
    				}
    			}
    		
  16. Right-click the project name (PDFFormExample) in the Solution Explorer > Deploy. This will deploy your new web part to the local SharePoint site you specificed when creating the project.

  17. Browse to your local SharePoint site. Add your new web part to a SharePoint page (will be under the Custom category).

  18. Submit some data. If all goes well, it should indicate the form was successfully submitted.

  19. You should now have a complete form in the Completed Forms library.

That’s it. You are now able to retrieve a PDF Form, fill it out programmatically, and save it back to SharePoint. Now it’s your turn to find good uses for this.

Share on TwitterShare on LinkedInShare on TumblrSubmit to StumbleUponSave on DeliciousDigg ThisSubmit to reddit

John Chapman

Hello, I'm John Chapman. I am a SharePoint developer living in Denver, Colorado. I develop solutions using ASP.NET, C#, jQuery, SQL, SharePoint, etc, and I thrive on the challenge of writing code to overcome the impossible, annoying, or otherwise difficult obstacles.

More Posts - Website - Twitter

5 Comments

  • Great stuff. Thanks for the article really helped me out. Had an issue with the itextsharp dll not deploying to the server. Fixed it by adding it to the package.

  • Can this solution be used to host forms for fill out? I gather that this particular solution, as-coded above, is for inserting data into the form from a data source, or am I mistaken.

    I also need to know if this will work with forms created with LC Designer 9. (Dynamic XML Forms)

  • Greate code sample, thanks!

    My only problem now is that I can’t edit the form fields once the form has been migrated over to the completed forms list. The required text is in the field, but the fields arent hi lighted any more. For instance, if the institution name needs changed, it wont allow me to change it.

    Should the form fields be left editable? Is there something I am missing?

    Thanks,
    Mike

  • Here is the reason why I should do 10 minutes of research before posting replies to code samples::

    Fattening is the process of removing the editable fields in a pdf before saving…. I changed the code to pdf.flattening = false; and it worked like a champ….

    Thanks again for the useful code!!

    Mike

    • Glad you found what you were looking for :-)

Leave a comment

John Chapman