[reportlab-users] Forms & the canvas

Ian Sparks Ian.Sparks at etrials.com
Thu Jul 7 11:09:53 EDT 2005


This was a head-scratcher so I'm posting it here in case it helps someone else out.

Be be careful when defining PDF forms via beginForm() and endForm() that canvas operations between beginForm and endForm ignore the current canvas state.

Lets say you have a function drawBox() :

def drawBox(canv):
    """Draw an inch-square box on the canvas"""
    canv.rect(5 * inch,-1 * inch,inch,-inch)

Notice that this function assumes that the origin is at the top of the page - it draws an inch from the top. That means you have to have first done the translate to move the origin :

You might be tempted to :

    #Define it
    canv.translate(0,11 * inch) #Make origin to left corner of letter portrait page
    canv.beginForm('test')
    drawBox(canv)
    canv.endForm()

    #Print it
    canv.doForm('test')

But that won't work because PDF forms draw to their own plane of existance outside of the current canvas context. That means that all operations you do to the canvas before beginForm() are ignored between the beginForm() and endForm() operation. No scaling, translation, skew, line-widths, color settings etc are maintained and the origin is back to 0,0 (bottom left of page) as if you were working with a new document.

You need to do all your canvas operations INSIDE the beginForm(), endForm() pair :


    #Define it
    canv.beginForm('test')
    canv.translate(0,11 * inch) #Make origin to left corner of letter portrait page    
    drawBox(canv)
    canv.endForm()

    #Print it
    canv.doForm('test')

This is obvious when you think about what beginForm() and endForm() are doing but because beginForm() and endForm() are methods of the canvas it's easy to forget that and get confused about where your settings went.

An extra paragraph in the manual would have saved me some pain. What about :

ch3_pdffeatures.py :

eg(examples.testforms)
disc("""NOTE : All canvas operations between beginForm() and endForm()
     are working in a private canvas that ignores the state
     of the existing canvas. All existing color settings, translations, 
     scaling etc are ignored inside the Form. However, when the Form
     is draw it is drawn into the current canvas and will use the
     current canvas settings :
    """)
eg(examples.testformscanvstate)

examples.py :

testformscanvstate = """
def forms(canvas):

    canvas.setStrokeColor(colors.green) #Set stroke color green This will be ignored by the form contents    

    canvas.beginForm("TestForm")
    canvas.rect(0,inch,inch,inch) #Draw an inch-square box.
    spumoni(canvas)
    canvas.endForm()

    #draw it (the box will be in green)
    canvas.doForm("SpumoniForm")

    canvas.setStrokeColor(colors.black)

    #draw it (the box will be in black)
    canvas.doForm("SpumoniForm")
    
"""



More information about the reportlab-users mailing list