Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add multiple lines at bottom (footer) of PDF?

I have to create PDF file in which need to add lines at bottom left like footer.

Following code is working:

import StringIO
from reportlab.pdfgen import canvas
import uuid

def test(pdf_file_name="abc.pdf", pdf_size=(432, 648), font_details=("Times-Roman", 9)):
    # create a new PDF with Reportla 
    text_to_add = "I am writing here.."
    new_pdf = "test_%s.pdf"%(str(uuid.uuid4()))

    packet = StringIO.StringIO() 
    packet.seek(0)

    c = canvas.Canvas(pdf_file_name, pagesize = pdf_size)
    #- Get the length of text in a PDF. 
    text_len = c.stringWidth(text_to_add, font_details[0], font_details[1])
    #- take margin 20 and 20 in both axis 
    #- Adjust starting point on x axis according to  text_len
    x = pdf_size[0]-20  -  text_len
    y = 20 
    #- set font.
    c.setFont(font_details[0], font_details[1])
    #- write text,
    c.drawString(x, y, text_to_add)

    c.showPage()
    c.save()
    return pdf_file_name

Now if text have multiple lines then this is not working because length of text is greater than width of Page size. Understood.

I try with Frame and paragraph but still can not write text in correct position in a PDF

Following is code:

from reportlab.lib.pagesizes import letter
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import BaseDocTemplate, Frame, PageTemplate, Paragraph

styles = getSampleStyleSheet()
styleN = styles['Normal']
styleH = styles['Heading1']

def footer(canvas, doc):
    canvas.saveState()
    P = Paragraph("This is a multi-line footer.  It goes on every page.  " * 10, styleN)
    w, h = P.wrap(doc.width, doc.bottomMargin)
    print "w, h:", w, h
    print "doc.leftMargin:", doc.leftMargin
    P.drawOn(canvas, 10, 30)
    canvas.restoreState()

def test():
    doc = BaseDocTemplate('test.pdf', pagesize=(432, 648))
    print "doc.leftMargin:", doc.leftMargin
    print "doc.bottomMargin:", doc.bottomMargin
    print "doc.width:", doc.width  
    print "doc.height:", doc.height
    frame = Frame(10, 50, 432, 648, id='normal')
    template = PageTemplate(id='test', frames=frame, onPage=footer)
    doc.addPageTemplates([template])

    text = []
    for i in range(1):
        text.append(Paragraph("", styleN))

    doc.build(text) 

Not understand why size of page change, because I set (432, 648) but is show (288.0, 504.0)

doc.leftMargin: 72.0
doc.bottomMargin: 72.0
doc.width: 288.0
doc.height: 504.0

Also Frame size:

w, h: 288.0 96
doc.leftMargin: 72.0

Do not know how to fix this issue. I refer this link

like image 469
Vivek Sable Avatar asked Jan 29 '16 10:01

Vivek Sable


1 Answers

First the mystery regarding the doc.width, the doc.width isn't the actual width of the document. It is the width of the area between the margins so in this case doc.width + doc.leftMargin + doc.rightMargin equals the width of the actual page.

Now back to why the footer did not span the entire width of the page as you wanted. This is because of the same issue as described above, namely doc.width isn't the actual paper width.

Assuming you want the footer to span the entire page

def footer(canvas, doc):
    canvas.saveState()

    P = Paragraph("This is a multi-line footer.  It goes on every page.  " * 10, styleN)

    # Notice the letter[0] which is the width of the letter page size
    w, h = P.wrap(letter[0] - 20, doc.bottomMargin)

    P.drawOn(canvas, 10, 10)
    canvas.restoreState()

Assuming you want the footer to span the width of the writable area

Note: the margins on the default setting are pretty big so that is why there is so much empty space on the sides.

def footer(canvas, doc):
    canvas.saveState()
    P = Paragraph("This is a multi-line footer.  It goes on every page.  " * 10, styleN)
    w, h = P.wrap(doc.width, doc.bottomMargin)
    print "w, h:", w, h
    print "doc.leftMargin:", doc.leftMargin
    P.drawOn(canvas, doc.leftMargin, 10)
    canvas.restoreState()

EDIT:

As it might be useful to know where the normal text should start. We need to figure out the height of our footer. Under normal circumstances we cannot use P.height as it depends on the width of the text, calling it will raise a AttributeError.

In our case we actually are able to get the height of the footer either directly from P.wrap (the h) or by calling P.height after we have called P.wrap.

By starting our Frame at the height of the footer we will never have overlapping text. Yet it is important to remember to set the height of the Frame to doc.height - footer.height to ensure the text won't be placed outside the page.

like image 77
B8vrede Avatar answered Nov 11 '22 22:11

B8vrede