This blog will cover some of the complexities that lurk behind programmatically creating, editing, or filling in a text form field in a PDF document using DotPdf.
There are a number of challenges in presenting an API for a “simple” PDF text field (in our API, it's a TextWidgetAnnotation). There has to be a balance between hiding complexity and presenting flexibility. This is even more challenging because the PDF specification for how the contents of a text field should appear has gone through three completelu different and largely incompatible revisions over the current life of the PDF specification.
In DotPdf, I try to shield you from the complexities of the PDF specification. In this case, I’m left somewhat helpless because of the changes in PDF.
The possibilities for how a text field may appear include:
- Nothing supplied. Your viewer makes the decision on how the field contents appear.
- A default appearance. In PDF this is an embedded string of PDF text-state operators that inform the PDF viewer how to make text appear. Instead of making clients build a string that contains something like “/Helv 12.0 Tf”, I offer a high-level abstraction of text styling and use that to build the string for you. If you provide only this, a PDF viewer is likely to figure out how to render your field.
- A default appearance and an appearance stream. Appearance streams in PDF are complicated. They are a representation of an RPN program that is executed to render graphics. Every field (and text fields are only one type of field) can have up to three sets of appearance for viewing conditions: Normal, Activated, and Rollover. I offer you a high level object called a DrawingTemplate which is a much higher level abstraction of a PDF appearance. I will automatically generate this for you at your request.
- Rich Text. If you provide Rich Text, you can include a limited XHTML string that will be used to create styling for the contents of a text field.
One problem you might encounter is that when you programmatically fill in the contents of a text form field, you don’t get what you expect to see. In fact, you may see nothing at all.
In using DotPdf to fill in form fields, you should ask yourself three questions:
- What did I get from the file?
- What do I have?
- What do I want in the output?
If you want the output to as closely match the input as possible, you need to be aware of the following properties in TextWidgetAnnotation:
- TextValue, DefaultTextValue – this set the content text of the annotation if there is nothing else
- RichTextValue, DefaultRichTextStyleString – these will determine how the text content and styling if a viewer supports it and in Acrobat it will silently override TextValue.
- DefaultTextAppearance – this will set the styling of text if there is no RichTextValue. It’s unclear from the specification how a viewer should behave if there are both.
- Appearance – a set of names of DrawingTemplate objects that determine how the UI of the TextWidgetAnnotation should appear on the page.
These elements comprise the first question, “what did I get?”
“What do I have?” is your domain. Maybe you only have text to fill in. Maybe have text and basic font information. Maybe you have styling.
“What do I want?” is also your domain. Maybe you don’t care about the document author’s intent – you just want to put in your own appearance. Maybe you care about the author’s intent – in this case you’ll want to honor the RichText if present.
If you wanted to simply enter field data, what I would do is this:
- Set Appearance to null.
- Set AutoGenerateBasicAppearance to true.
- Set RichTextValue to null.
- Set TextValue to the string you want
- Set DefaultTextAppearance to the font characteristics you want (or to null for default)
In TextWidgetAnnotation, I provide the tool used for making a text field’s appearance in the static method MakeBasicAppearance(…). If you didn’t want to create your own appearance sets, but just wanted to style mine, you could do that like this:
This is all you need to have a simple form field. If you wanted something more dynamic that made it clear that you had a UI element for your document users to work with, it’s not much more work than the previous example. In fact, we can parameterize it more. One note – in the previous example, the string “N” is used to identify a specific state that the annotation is in. In some widget annotations there could be separate entries for “Off” and “On” or perhaps “Visa”, “MasterCard”, “Amex”, “Discover”. If there is only one state, the string is inconsequential.
public static void StyleTextField(GlobalResources gr, TextWidgetAnnotation tf, Color fill, AppearanceStates states)
string name = MakeBasicAppearance(gr, tf.Bounds, tf.DefaultTextAppearance, 1.0, PdfColorFactory.FromColor(Color.Black);
Then you can do this in your code:
StyleTextField(doc.Resources, yourfield, normalColor, yourfield.Appearance.Normal);
StyleTextField(doc.Resources, yourfield, rolloverColor, yourfield.Appearance.Rollover);
We can see that even though the PDF specification provides a very complicated set of possible ways to skin a text field, DotPdf provides you with the tools to make all the possibilities straightforward and customizable.
About the Author
Steve was with Atalasoft from 2005 until 2015. He was responsible for the architecture and development of DotImage, and one of the masterminds behind Bacon Day. Steve has over 20 years of experience with companies like Bell Communications Research, Adobe Systems, Newfire, Presto Technologies.Follow on Twitter More Content by Steve Hawley