During a recent project I decided to provide the ability for my users to fill in a PDF form directly from within my application. Basically my application would be the shell to a PDF viewer controlled by our application.

This had three immediate benefits for my application:
1. I didn't have to spend 5 years developing complicated User Controls only to be constantly changing them to keep up with the paper forms.
2. People didn't have to relearn how to enter the data since the PDF WAS the paper form.
3. Rendering a completed 'form' for printing would have been very difficult and time consuming, instead users could simply fill the form fields and then print it out.

Development Environment

My development environment is Visual Studio 2003 targetting the DotNet platform version 1.1. The development machine has 2Gigs of RAM and plenty'o'disk space.

The version of Acrobat being used to develop the PDF forms is version 6, with the PDF form files at PDF version 1.4 (Acrobat 5 compatible).

Basic Component Requirements

I needed five things from our PDF component:
  • View a PDF document internally inside our app,
  • Fill in the PDF directly via the viewer,
  • .NET Component (or wrapped ActiveX),
  • Print the PDF as controlled by our app.
  • Programmatic access to the form fields and event handlers.
  • Finding the right component

    Being involved with PDF since the start and being a developer for over 10 years I took it for granted that we'd be able to find a PDF component that would match all of our requirements - in fact I would go as far as to say that I thought I would have trouble choosing between them based on other factors (like cost or support).

    This couldn't be farther from the truth. Not only did I have to review 7 different 'PDF vendors' but I also had to triple check that each of the components offered actually had the five things we were looking for.

    So using our 5 'must-have' features I knocked out 5 components immediately, they either didn't have the ability to enter data into the form, couldn't print or required an expensive OEM agreement to read a completed PDF form.

    After emailing the support email addresses from the remaining two vendors it was very clear which vendor had their priorities right: Amyuni.(http://www.amyuni.com/)

    This might just be my bias but I judge a company based on it's after sales support. In this case I hadn't even purchased the product and was receiving extensive code samples, answers to questions and component advice. To say that I was impressed is an understatement.

    So I had found the component: Amyuni PDF Creator.Net.

    Price Point

    In this case I wasn't so much concerned about the cost as I was about the functionality. If the component couldn't do my top five then it was a no brainer and if it could do it then provided it wasn't prohibitively expensive I would wear it.

    After spending almost 8 hours reviewing components and their features/prices etc the Amyuni PDF Creator.NET at $920US wasn't the cheapest component but certainly wasn't the most expensive.

    Testing the Top Five

    Not being content with believing what I read (especially not since I've been burned with software components before) I developed a sample application that could accomplish each of the five requirements.

    The documentation that came with Amyuni is complete however I found to be difficult to understand, I could find the information I was looking for only after being told about it by Amyuni support. This was/is a real disappoint to me since I had never used a PDF component in this way before so having documentation that could get me going and get me going really quick would've been great.

    But this is where the support comes in. After emailing my concerns the support team sent me entire VS solutions that addressed - via code, my top five. After further emails and after I had built a working prototype I knew that the PDF Creator.Net component was the one to buy.

    Seeing it in Action

    Viewing a PDF Document

    I started with the basic premise that once complete, the PDF documents would live as 'embedded resources' within the compiled assemblies (DLL's). This provided some protection for me as it prevents the PDF from being altered on the file system.

    The basic idea to be able to view a PDF document from within your own application is to drag and drop the PDFCreator visual component onto a design surface such as a winform or usercontrol (in my case a custom usercontrol). Then programmatically load a PDF document as a stream into the component.

    Since my component was an embedded resource I only had four lines of code to load the PDF into the PDF Viewing component:

    Assembly assem = Assembly.GetExecutingAssembly();
    Stream pdfStream = null;
    pdfStream = assem.GetManifestResourceStream(resourceName);
    pdfCreator.Document.Open(pdfStream,"");

    (this whole thing is wrapped in a try/catch block).

    The resourceName parameter is the fully qualified namespace etal to the embedded resource. If you want to find out what your embedded resource 'paths' are use the 'assem.GetManifestResourceNames();' method. The second parameter to the 'Document.Open' method is the password to open the PDF.

    Filling in the Form

    Once the application was started and the PDF visible in my application I was presented with a ruler, document page (which had my loaded PDF on it) and statusbar with page turning controls.

    Actually entering the data into the form fields is just like Acrobat, enter data then tab to the next field.

    .NET Component

    Because this component isn't a 100% .NET component it means there's a lot more room for error since more messages are being sent back and forth between the .NET runtime and your control and your application. So my biggest concern was that somewhere along the lines one of the messages wouldn't be handled properly and the whole deck of cards would come crashing down.

    This just wasn't the case, after four days of heavy testing I only found out one thing: PDFCreator.Net doesnt like forms with over 400 fields, the component was unresponsive and generally took ages to do anything. But I'm lucky in that my requirements are for roughly 100 fields per PDF form.

    Printing

    After I had loaded a PDF and entered my test data and selected my checkboxes I pushed the test print button that I had hooked up.

    With one line of code the print preview dialog box is displayed:

    pdfCreator.Document.Print("", true);

    There are a lot of properties available for printing, including setting the tray, paper sizes and number of copies but for me all I wanted to do was print the PDF out.

    To ensure that my users had actually wanted to print the document there's an event you can register for to notify you once the print method has been called and if the user didn't mean to push print you can cancel the event. The other reason this is useful is if you wanted to setup the printer before printing to it or check that the printer is actually online.

    To get a fair comparison I printed the same filled in PDF from Acrobat and then from Amyuni and with only slight variation in the page margins there was no difference at all to the quality.

    Programmatic Access

    The last requirement was to have programmatic access to both retrieving the value of a form field and setting the value of a form field.

    For example if we wanted to get the value from a text form field we would do something like this:

    IacObject formObj = pdfCreator.Document.ObjectByName("fieldname");
    IacAttribute formAttr = formObj.AttributeByName("Value");
    string formValue = formAttr.Value as string;

    The gotcha is that if a field DOESNT have a value then the Attribute 'Value' would be null, so it's important to wrap accessor calls in a try/catch.

    For me I created a generic class that handles all of my call to and from the fields and also provides utility methods for getting the IacObjects and IacAttribute objects.

    Where Does it Let you down?

    Event handling

    Although listed in the documentation I haven't been able to add event handlers to individual buttons or checkboxes. You can however hook into the event handlers at the Document level of which there are MANY events.

    I solved the problem of working out which button was pressed by checking the name of the field and responding accordingly, as it turns out this wasnt a big deal as I have a relatively small number of buttons and they share common functionality.

    This point might be a non-event as I might be misunderstanding the documentation and wiring them up incorrectly.

    Documentation

    As I mentioned above the documentation seems complete but just doesnt have a good flow. This can make it difficult when you are coming to an API fresh.

    The documentation could do with a good injection of diagrams, better and more complete code samples and a better flowing structure.

    ListBoxes

    There's no support for multiple selections in listboxes. Now at first this was a big problem for me, but I eventually solved it by adding a button that presented a Windows Form with a list of items and then passing back the list of selected items to the appropriate field (comma delimited).

    In the end I didn't miss this feature because my project could live without it, other people may not feel this way in which case I'd contact Amyuni and pester them to include it. If enough people request the feature then I'm sure they listen.

    Radio Buttons

    Unfortunately the component doesnt yet support grouped radio (or checkbox) buttons. This means that when I user clicks on the 'Male' radio button the 'Female' radio button doesnt uncheck/clear.

    The solution to this problem was to hook into the event handler for the PDF Document (a property of the PDFCreator component, and uncheck manually the appropriate field. I accomplished this in a very generic way by only catching events that were triggered by checkboxes/radiobuttons and checking the last character of the field name. If the field name had a 'Y' on the end then I knew to turn off the corresponding 'N' field.

    As a rule I don't like workaround like this as at some point something will change in the PDF and render my generic solution useless.

    Javascript

    I initially hoped that I could solve any deficiencies in the API by simply writing javascript behind non-printable buttons. Unfortunately none of the javascript I wrote worked in the PDF when I viewed it with the PDF Creator.Net component.

    I would love to see this implemented in future versions of the component as it would allow form developers to provide better form validation and interaction in the PDF.

    API

    It's not the easiest of API's the follow, but that has a lot to do with the complexity of writing such a component.

    The multiple layering of properties inside objects inside properties was difficult at first, only after seeing real code sample was I able to make the connections needed to do what I needed to do.

    Summary

    I can't stress enough that the support from Amyuni has been outstanding, this above all else swayed me to choose Amyuni PDF Creator.Net. There's nothing worse than being on a tight deadline trying to complete the job and not being able to get timely and accurate support, Amyuni need to be commended here on putting support as a top priority.

    As you can tell there were some areas that disappointed me (grouping of radio buttons, complicated API etc) but these were outweighed in my case by the functionality of the component and it's general stability in loading and navigating the PDFs.

    So if your considering which PDF component to use next or even trying to sort out the good PDF vendors from the OK ones then I hope this article helps.

    Resources

    I used my own PDF Web Links list to find the first list of PDF Vendors: http://www.acrotips.com/links/index.php

    I found at this site an initial bouncing platform for finding PDF vendors: http://www.xtras.net/categories/PDF/