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 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:
This same file displayed in our DisplayPDF sample app does not display these values:
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:
I hope you found this post helpful! Feel free to leave us a comment with any questions or tips of your own.