Some test text!

platform
search
< Linux samples

PDF Interactive Forms (AcroForms) in Python

Sample Python code for using PDFTron SDK with interactive forms (also known as AcroForms). Capabilities include programatically creating new fields and widget annotations, form filling, modifying existing field values, form templating, and flattening form fields. Learn more about our PDF Form Filler SDK.

Step 1: Get your free trial license key, or sign in

Start Trial
Sign in

Step 2: Add the code:

#---------------------------------------------------------------------------------------
# Copyright (c) 2001-2019 by PDFTron Systems Inc. All Rights Reserved.
# Consult LICENSE.txt regarding license information.
#---------------------------------------------------------------------------------------

import site
site.addsitedir("../../../PDFNetC/Lib")
import sys
from PDFNetPython import *

# Relative path to the folder containing the test files.
input_path = "../../TestFiles/"
output_path = "../../TestFiles/Output/"

#---------------------------------------------------------------------------------------
# This sample illustrates basic PDFNet capabilities related to interactive 
# forms (also known as AcroForms). 
#---------------------------------------------------------------------------------------

def RenameAllFields(doc, name):
    itr = doc.GetFieldIterator(name)
    counter = 0
    while itr.HasNext():
        f = itr.Current()
        f.Rename(name + str(counter))
        itr = doc.GetFieldIterator(name)
        counter = counter + 1

# Note: The visual appearance of check-marks and radio-buttons in PDF documents is 
# not limited to CheckStyle-s. It is possible to create a visual appearance using 
# arbitrary glyph, text, raster image, or path object. Although most PDF producers 
# limit the options to the above 'standard' styles, using PDFNet you can generate 
# arbitrary appearances.
def CreateCheckmarkAppearance(doc):
    # Create a checkmark appearance stream ------------------------------------
    build = ElementBuilder()
    writer = ElementWriter()
    writer.Begin(doc.GetSDFDoc())
    writer.WriteElement(build.CreateTextBegin())
    
    symbol = "4"
    # other options are circle ("l"), diamond ("H"), cross ("\x35")
    # See section D.4 "ZapfDingbats Set and Encoding" in PDF Reference Manual for 
    # the complete graphical map for ZapfDingbats font.
    checkmark = build.CreateTextRun(symbol, Font.Create(doc.GetSDFDoc(), Font.e_zapf_dingbats), 1)
    writer.WriteElement(checkmark)
    writer.WriteElement(build.CreateTextEnd())
    
    stm = writer.End()
    
    # Set the bounding box
    stm.PutRect("BBox", -0.2, -0.2, 1, 1)
    stm.PutName("Subtype","Form")
    return stm

def CreateButtonAppearance(doc, button_down):
    # Create a button appearance stream ------------------------------------
    build = ElementBuilder()
    writer = ElementWriter()
    writer.Begin(doc.GetSDFDoc())
    
    # Draw background
    element = build.CreateRect(0, 0, 101, 37)
    element.SetPathFill(True)
    element.SetPathStroke(False)
    element.GetGState().SetFillColorSpace(ColorSpace.CreateDeviceGray())
    element.GetGState().SetFillColor(ColorPt(0.75, 0, 0))
    writer.WriteElement(element)
    
    # Draw 'Submit' text
    writer.WriteElement(build.CreateTextBegin())
    text = "Submit"
    element = build.CreateTextRun(text, Font.Create(doc.GetSDFDoc(), Font.e_helvetica_bold), 12)
    element.GetGState().SetFillColor(ColorPt(0, 0, 0))
    
    if button_down:
        element.SetTextMatrix(1, 0, 0, 1, 33, 10)
    else:
        element.SetTextMatrix(1, 0, 0, 1, 30, 13)
    writer.WriteElement(element)
    
    writer.WritePlacedElement(build.CreateTextEnd())
    
    stm = writer.End()
    
    # Set the bounding box
    stm.PutRect("BBox", 0, 0, 101, 37)
    stm.PutName("Subtype","Form")
    return stm
    

def main():
    PDFNet.Initialize()
    
    
    #----------------------------------------------------------------------------------
    # Example 1: Programatically create new Form Fields and Widget Annotations.
    #----------------------------------------------------------------------------------
    
    doc = PDFDoc()
    blank_page = doc.PageCreate()  # Create a blank new page and add some form fields.
    
    # Create new fields.
    emp_first_name = doc.FieldCreate("employee.name.first", Field.e_text, "John", "")
    emp_last_name = doc.FieldCreate("employee.name.last", Field.e_text, "Doe", "")
    emp_last_check1 = doc.FieldCreate("employee.name.check1", Field.e_check, "Yes", "")
    
    submit = doc.FieldCreate("submit", Field.e_button)
    
    # Create page annotations for the above fields.
    
    # Create text annotations
    annot1 = Widget.Create(doc.GetSDFDoc(), Rect(50, 550, 350, 600), emp_first_name)
    annot2 = Widget.Create(doc.GetSDFDoc(), Rect(50, 450, 350, 500), emp_last_name)
    
    # Create a check-box annotation
    annot3 = Widget.Create(doc.GetSDFDoc(), Rect(64, 356, 120, 410), emp_last_check1)
    # Set the annotation appearance for the "yes" state...
    annot3.SetAppearance(CreateCheckmarkAppearance(doc), Annot.e_normal, "Yes")
    
    # Create button annotation
    annot4 = Widget.Create(doc.GetSDFDoc(), Rect(64, 284, 163, 320), submit)
    
    # Set the annotation appearances for the down and up state...
    annot4.SetAppearance(CreateButtonAppearance(doc, False), Annot.e_normal)
    annot4.SetAppearance(CreateButtonAppearance(doc, True), Annot.e_down)
    
    # Create 'SubmitForm' action. The action will be linked to the button.
    url = FileSpec.CreateURL(doc.GetSDFDoc(), "http://www.pdftron.com")
    button_action = Action.CreateSubmitForm(url)
    
    # Associate the above action with 'Down' event in annotations action dictionary.
    annot_action = annot4.GetSDFObj().PutDict("AA")
    annot_action.Put("D", button_action.GetSDFObj())
    
    blank_page.AnnotPushBack(annot1) # Add annotations to the page
    blank_page.AnnotPushBack(annot2)
    blank_page.AnnotPushBack(annot3)
    blank_page.AnnotPushBack(annot4)  
    
    doc.PagePushBack(blank_page)    # Add the page as the last page in the document.                    
                                     
    # If you are not satisfied with the look of default auto-generated appearance 
    # streams you can delete "AP" entry from the Widget annotation and set 
    # "NeedAppearances" flag in AcroForm dictionary:
    #    doc.GetAcroForm().PutBool("NeedAppearances", true);
    # This will force the viewer application to auto-generate new appearance streams 
    # every time the document is opened.
    #
    # Alternatively you can generate custom annotation appearance using ElementWriter 
    # and then set the "AP" entry in the widget dictionary to the new appearance
    # stream.
    #
    # Yet another option is to pre-populate field entries with dummy text. When 
    # you edit the field values using PDFNet the new field appearances will match 
    # the old ones.

    #doc.GetAcroForm().PutBool("NeedAppearances", True)
    doc.RefreshFieldAppearances()
    
    doc.Save(output_path + "forms_test1.pdf", 0)
    doc.Close()
    print("Done.")
    
    #----------------------------------------------------------------------------------
    # Example 2: 
    # Fill-in forms / Modify values of existing fields.
    # Traverse all form fields in the document (and print(out their names). 
    # Search for specific fields in the document.
    #----------------------------------------------------------------------------------
    
    doc = PDFDoc(output_path + "forms_test1.pdf")
    doc.InitSecurityHandler()
    
    itr = doc.GetFieldIterator()
    while itr.HasNext():
        print("Field name:" + itr.Current().GetName())
        print("Field partial name: " + itr.Current().GetPartialName())
        
        print("Field type: ")
        type = itr.Current().GetType()
        str_val = itr.Current().GetValueAsString()
        if type == Field.e_button:
            print("Button")
        elif type == Field.e_radio:
            print(" Radio button: Value = " + str_val)
        elif type == Field.e_check:
            print("Check box: Value = " + str_val)
            sv = itr.Current().SetValue(True)
        elif type == Field.e_text:
            print("Text")
            # Edit all variable text in the document
            sv = itr.Current().SetValue("This is a new value. The old one was: " + str_val)
        elif type == Field.e_choice:
            print("Choice")
        elif type == Field.e_signature:
            print("Signiture")
        print("------------------------------")
        itr.Next()
    # Search for a specific field
    f = doc.GetField("employee.name.first")
    if f != None:
        print("Field search for " + f.GetName() + " was successful")
    else:
        print("Field search failed")
        
    # Regenerate field appearances.
    doc.RefreshFieldAppearances()
    doc.Save(output_path + "forms_test_edit.pdf", 0)
    doc.Close()
    print("Done.")
    
    #----------------------------------------------------------------------------------
    # Sample: Form templating
    # Replicate pages and form data within a document. Then rename field names to make 
    # them unique.
    #----------------------------------------------------------------------------------
    
    # Sample: Copying the page with forms within the same document
    doc = PDFDoc(output_path + "forms_test1.pdf")
    doc.InitSecurityHandler()
    
    src_page = doc.GetPage(1)
    doc.PagePushBack(src_page) # Append several copies of the first page
    doc.PagePushBack(src_page) # Note that forms are successfully copied
    doc.PagePushBack(src_page)
    doc.PagePushBack(src_page)
    
    # Now we rename fields in order to make every field unique.
    # You can use this technique for dynamic template filling where you have a 'master'
    # form page that should be replicated, but with unique field names on every page. 
    RenameAllFields(doc, "employee.name.first")
    RenameAllFields(doc, "employee.name.last")
    RenameAllFields(doc, "employee.name.check1")
    RenameAllFields(doc, "submit")
    
    doc.Save(output_path + "forms_test1_cloned.pdf", 0)
    doc.Close()
    print("Done.")
    
    #----------------------------------------------------------------------------------
    # Sample: 
    # Flatten all form fields in a document.
    # Note that this sample is intended to show that it is possible to flatten
    # individual fields. PDFNet provides a utility function PDFDoc.FlattenAnnotations()
    # that will automatically flatten all fields.
    #----------------------------------------------------------------------------------
    doc = PDFDoc(output_path + "forms_test1.pdf")
    doc.InitSecurityHandler()
     
    # Traverse all pages
    if False:
        doc.FlattenAnnotations()
    else: # Manual flattening
        pitr = doc.GetPageIterator()
        while pitr.HasNext():
            page = pitr.Current()
            annots = page.GetAnnots()
            if annots is not None:
                # Look for all widget annotations (in reverse order)
                i = annots.Size()- 1
                while i >= 0:
                    if annots.GetAt(i).Get("Subtype").Value().GetName() == "Widget":
                        field = Field(annots.GetAt(i))
                        field.Flatten(page)
                        
                        # Another way of making a read only field is by modifying 
                        # field's e_read_only flag: 
                        # field.SetFlag(Field.e_read_only, True)
                    i = i - 1
            pitr.Next()

    doc.Save(output_path + "forms_test1_flattened.pdf", 0)
    doc.Close()
    print("Done.")
        
if __name__ == '__main__':
    main()