Sample of the Week: Fixing Blank AcroForms Using APDFL

Sample of the Week: Fixing Blank AcroForms Using APDFL

Every so often, we run into a situation where a user is printing an AcroForm PDF with APDFL, and the print output is blank. The information is there when viewed in and printed in Acrobat, but the same document is blank when printed or viewed from APDFL.  Oftentimes, it’s reported as a bug when it’s not actually a bug.

What’s often happening in those cases is that the form field’s values were updated by an automated process but without updating the appearance of the widgets associated with those form fields.  Instead, a ‘NeedsAppearances’ flag is set.  This flag tells Acrobat to re-generate the appearances of those widgets from the properties of the field and/or widget annotation.  Acrobat looks for this flag when it opens a document and regenerates those appearances automatically.

Luckily, we can use APDFL to approximate the Acrobat’s process of regenerating Normal Appearance Streams for Text Widget Annotations.  In this case, we are going to use our .Net interface rather than the APDFL C interface directly.

The first step will be to populate a font lookup table with the names of the PDF Standard-14 fonts:

Next, we are going to open the file and determine if it contains an AcroForm, and if it contains a Calculation Order entry. If it does contain such an entry, we are not going to process this document.  This entry implies that some field values are calculated from other field values via a JavaScript function. Fortunately, most of the time, we won’t see this value and all field values are final.

Next, we are going to check each annotation of the document to see if it might be a Widget annotation for a Text Field.  Widget Annotations often share the same dictionary record as its Text Field, however, a field could be displayed in multiple places in the document. In this case, the text field would have more than one Widget Annotation associated with it.  Since we are approaching the text field from the Annotation side, we need to check both if the annotation is the Text Field, or if its parent is the Text Field. Then we regenerate the Normal Appearance Stream.

Generating the Appearance Stream

When generating the Appearance Stream, the first thing we need to find is the DA string which contains initialization options.  Again, for this option, we will need to check both the Annotation itself and its Text Field parent.

The DA string contains options which are formatted like PDF instructions.  That makes it easy to parse if you have a PDF instruction parser on hand. If not, DA strings are generally short enough that brute-force string-parsing also works.

After that, we are going to use the information gleaned from the DA string to initialize things. We’re going to generate TextRuns and add them to a Text Element. The text Element will be added to a Group Element. The Group Element Added to a Container, and the Container added to a Form Element, which will be returned.  The PDF instructions generated from nesting the Text Element inside the Group element are slightly different than if the Text Element is added directly to the Container. The end result is an Appearance stream closer to how Acrobat generates the PDF Instructions for this same Widget Annotation.  I did take one shortcut here, where I make no attempt to line-wrap the text to fit the box;  it’s not often needed for forms.

One last fix-up to the Form dictionary, and we are all done regenerating the appearance for this annotation:


So let’s take a look at how this handles an example form to which I added values to the text fields, as rendered by Acrobat:

A PDF form without appearance streams rendered in Acrobat

This same file displayed in our DisplayPDF sample app does not display these values:

Same PDF Form Rendered in our DisplayPDF sample app

But if I run that file through the AddTextWidgetAppearances sample app and take a look at the output file in DisplayPDF, then the field values look pretty close to how Acrobat rendered them:

The same PDF form rendered in DisplayPDF after its Appearance Streams are generated by AddTextWidgetAppearances

I hope you found this post helpful! Feel free to leave us a comment with any questions or tips of your own.

Leave a Reply

Your email address will not be published.