Draw images using canvas and use SimpleDocTemplate

I am writing pdfs with reportlab inside a django view, they are very simple, header, content and footer.

I use SimpleDocTemplate, which works very well to draw tables in the content, footer and drwan header using:

build([data], onFirstPage=drawPageFrame, onLaterPages=drawPageFrame). 

My question is: how can I draw an image, for example, using Canvas.drawImage (...)? I need a "floating" image ... located above the text where I want, and with SimpleDocTemplate I don't have a Canvas object for this.

Search I found this:

The table layout element uses streams. Packers typically set the canv attribute to each fluid when it is wrapped, split, or around wrapping, splitting, and drawing methods, for example. Inside these methods, you have access to the canvas using the canv self attribute.

How can this be used?

Ummmm, more testing material:

 flowables.Macro flowables.CallerMacro 
 # - * - coding: utf-8 - * -
 from reportlab.lib.pagesizes import A4, landscape, portrait
 from reportlab.lib.styles import getSampleStyleSheet
 from reportlab.platypus import Table, Flowable, SimpleDocTemplate, Paragraph, Spacer, Image
 from reportlab.lib import randomtext
 from reportlab import platypus

 import os, random

 styles = getSampleStyleSheet ()
 path = os.path.realpath (os.path.dirname (__ file__))

 def drawPageFrame (canvas, doc):
     canvas.saveState ()
     canvas.drawImage (path + "/ ujiPDF.jpg", 50,50,57,57)
     canvas.restoreState ()

 doc = SimpleDocTemplate ("salida.pdf", pagesize = A4)

 elementos = []

 com = 'canvas.drawImage ("' + path + '/ ujiPDF.jpg", 100,100,57,57)'
 print com
 elementos.append (platypus.flowables.Macro ('canvas.saveState ()'))
 print platypus.flowables.Macro (com)
 elementos.append (platypus.flowables.Macro (com))
 elementos.append (platypus.flowables.Macro ('canvas.restoreState ()'))

 para = Paragraph (randomtext.randomText (randomtext.PYTHON, 20), styles ["Normal"])
 elementos.append (para)

 doc.build (elementos, onFirstPage = drawPageFrame, onLaterPages = drawPageFrame)

This is a macro approach ... clean output, but without a second image.

+5
python django reportlab
source share
3 answers

Your best option is to create a subclass of SimpleDocTemplate or BaseDocTemplate. In the construction method, you will have access to the canvas. If you want to use everything that SimpleDocTemplate does, you can try copying it directly from site-packages/reportlab/platypus/doctemplate.py .

+2
source share

You do not need to subclass the entire document template, if I understand correctly, you just want you to be able to insert INTO into SimpleDocTemplate. You can achieve this with a very simple subclass of Flowable.

-> In particular, since people often ask about how to place matplotlib objects in reportlab, I will show how to generate a graph using matplotlib, and then use the modified flowable to place this graph in SimpleDocTemplate (without saving the file to disk). This concept applies to any file or something you can use in cStringIO

-> Below you can set the figure above the text (change the height from negative to positive to direct it above the imaginary line at the top of the section in which the plot goes)

The key concept is that each Flowable itself also contains a canvas that we can draw onto.

 import matplotlib.pyplot as plt import cStringIO from reportlab.lib.units import inch, cm from reportlab.lib.pagesizes import letter from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image, Table from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle import reportlab.lib, reportlab.platypus class flowable_fig(reportlab.platypus.Flowable): def __init__(self, imgdata): reportlab.platypus.Flowable.__init__(self) self.img = reportlab.lib.utils.ImageReader(imgdata) def draw(self): self.canv.drawImage(self.img, 0, 0, height = -2*inch, width=4*inch) # http://www.reportlab.com/apis/reportlab/2.4/pdfgen.html doc = SimpleDocTemplate(("report.pdf"),pagesize=letter, rightMargin=72,leftMargin=72, topMargin=72,bottomMargin=18) Story=[] styles=getSampleStyleSheet() ptext = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi massa dolor, vulputate quis elit sed, sagittis consectetur erat. Sed lobortis nisi eros, eu maximus enim iaculis ac. Vestibulum sagittis urna nec interdum aliquam. Pellentesque ornare velit ut ante ullamcorper, vulputate accumsan nisi vulputate. Fusce consectetur dolor quam. Phasellus hendrerit, ligula vel consectetur pretium, lorem neque dapibus eros, ornare suscipit ipsum dolor id nisl. Sed vel orci id leo efficitur lobortis sit amet id risus. Nullam euismod, ipsum a posuere scelerisque, ante lorem ultrices nibh, ut feugiat metus ex congue enim. Nam lobortis, metus id pellentesque feugiat, arcu orci rutrum felis, quis luctus urna nisl at nulla. Donec eu eros pharetra dolor congue facilisis at ac magna. Nullam eu ultricies metus. Sed sodales, libero viverra pellentesque tempus, magna purus convallis nibh, eu condimentum tortor erat tincidunt turpis. Vestibulum scelerisque tincidunt egestas. Nullam commodo diam nisl, sed consequat ex sagittis eu.' Story.append(Paragraph(ptext, styles["Normal"])) fig = plt.figure(figsize=(10, 3)) plt.plot([1,2,3,4]) plt.ylabel('This is a boring plot') imgdata = cStringIO.StringIO() fig.savefig(imgdata, format='png') imgdata.seek(0) # rewind the data pic = flowable_fig(imgdata) Story.append(pic) doc.build(Story) 

You can expand this minimal code to do whatever you like, and you can add as many elements to the Story variable (which is just a list of threads). The only magic is that we pass the constructor doc Flowable, which uses Flowable's own canvas to draw a figure.

EDIT: I almost forgot, because it gives us full access to drawImage, we can also make this picture or plot transparent, and through it you can see other things. There are details in drawImage docs.

+4
source share

There is an Image class in the platypus. Just use from reportlab.platypus import Image and you have access to this class. It works like the other classes inside, and smth.append(Image(filename)) adds the image to the object that needs to be created in pdf. Based on Tyler Lormann's Personal Site

+3
source share

All Articles