Python reportlab put an image in a canvasmaker
Question: I'd like to put an image (a barcode more precisely) in a pdf doc generated by
reportlab. I can put it in a table. That works perfectly with
createBarcodeDrawing().

The point is that I'd like the barcode to change on each page. Thus, I want to
put it in a canvasmaker.

Whatever method I use (drawImage(), drawInLineImage(),...), I always have an
error. I even tried to use CustomImage from [Reportlab [ Platypus ] - Image
does not render](http://stackoverflow.com/questions/13018786/reportlab-
platypus-image-does-not-render) without any success. Consequently, my question
is how can I draw an image in a canvas.Canvas ?

Can anybody help ? Thank you in advance Dom (I am not a professional)

Following a remark I read on <http://www.tylerlesmann.com/2009/jan/28/writing-
pdfs-python-adding-images/>, I tried:

    
    
    img = 'apple-logo.jpg'
    self.drawInlineImage('C:\\'+img,20,20)
    

This works, while 'C:\apple-logo.jpg' doesn't !! Nevertheless, I still don't
know how to draw my barcode without writing it to a file before! If someone
manages to do it, I would really appreciate. Bye

    
    
    from reportlab.pdfgen import canvas
    from reportlab.lib.units import mm
    
    
    class NumberedCanvas(canvas.Canvas):
    def __init__(self, *args, **kwargs):
        canvas.Canvas.__init__(self, *args, **kwargs)
        self._saved_page_states = []
    
    def showPage(self):
        self._saved_page_states.append(dict(self.__dict__))
        self._startPage()
    
    def save(self):
        """add page info to each page (page x of y)"""
        num_pages = len(self._saved_page_states)
        for state in self._saved_page_states:
            self.__dict__.update(state)
            page_num = self._pageNumber
            mybarcode = createBarcodeDrawing('QR', value= 'www.mousevspython.com - Page %s'%page_num)
            self.drawInlineImage(mybarcode,20,20)
            canvas.Canvas.showPage(self)
        canvas.Canvas.save(self)
    
    def main():
    import sys
    import urllib2
    from cStringIO import StringIO
    from reportlab.platypus import SimpleDocTemplate, Image, Paragraph, PageBreak
    from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet
    
    #This is needed because ReportLab accepts the StringIO as a file-like object,
    #but doesn't accept urllib2.urlopen's return value
    def get_image(url):
        u = urllib2.urlopen(url)
        return StringIO(u.read())
    
    styles = getSampleStyleSheet()
    styleN = ParagraphStyle(styles['Normal'])
    
    # build doc
    
    if len(sys.argv) > 1:
        fn = sys.argv[1]
    else:
        fn = "filename.pdf"
    doc = SimpleDocTemplate(open(fn, "wb"))
    elements = [
        Paragraph("Hello,", styleN),
        Image(get_image("http://www.red-dove.com/images/rdclogo.gif")),
        PageBreak(),
        Paragraph("world!", styleN),
        Image(get_image("http://www.python.org/images/python-logo.gif")),
    ]
    doc.build(elements, canvasmaker=NumberedCanvas)
    
    if __name__ == "__main__":
    main()
    


Answer: You were nearly there. Just replace `self.drawImage(mybarcode,20,20)` with
`mybarcode.drawOn(self, 20, 20)`. The barcode is not really an image, more an
barcode object which you can export to an image. As a side note: You are using
the NumberedCanvas which is kind of a hack to get the total page count. As i
see it you don't really need it, as you are just using the current page
number. If you don't need the total page count, you can just define a canvas
drawing function which draws the barcode on each page. For this you would do
something like this:

    
    
    def draw_barcode(canvas, doc):
        canvas.saveState()
        page_num = canvas._pageNumber
        mybarcode = createBarcodeDrawing('QR', value= 'www.mousevspython.com - Page %s'%page_num)
        mybarcode.drawOn(canvas, 20, 20)
        canvas.restoreState()
    

[...]

    
    
    # doc.build(elements, canvasmaker=NumberedCanvas)
    doc.build(elements, onFirstPage=draw_barcode, onLaterPages=draw_barcode)
    

