Proper way to add an image file inside a PDF docum

2019-05-31 04:54发布

I'm trying to generate a PDF report using reportlab on App Engine Python.

But I don't know how to attach an image properly.

The image is static.

This is the directory tree of my project.

enter image description here

and this is what I do (inside 'chipas.py') to get the image:

im = Image('../static/logo.png',1*inch, 1*inch)
story.append(im)
...

The stack trace I get:

Traceback (most recent call last): File "C:\Users\Lucas\Dropbox\Desarrollo\Python\windows\AppEngine\google\appengine\ext\webapp_webapp25.py", line 701, in call handler.get(*groups) File "C:\Users\Lucas\Dropbox\Desarrollo\workspace\python\chipas-windows\src\chipas.py", line 1035, in get doc.build(story) File "C:\Users\Lucas\Dropbox\Desarrollo\workspace\python\chipas-windows\src\reportlab\platypus\doctemplate.py", line 1117, in build BaseDocTemplate.build(self,flowables, canvasmaker=canvasmaker) File "C:\Users\Lucas\Dropbox\Desarrollo\workspace\python\chipas-windows\src\reportlab\platypus\doctemplate.py", line 880, in build self.handle_flowable(flowables) File "C:\Users\Lucas\Dropbox\Desarrollo\workspace\python\chipas-windows\src\reportlab\platypus\doctemplate.py", line 763, in handle_flowable if frame.add(f, canv, trySplit=self.allowSplitting): File "C:\Users\Lucas\Dropbox\Desarrollo\workspace\python\chipas-windows\src\reportlab\platypus\frames.py", line 159, in _add w, h = flowable.wrap(aW, h) File "C:\Users\Lucas\Dropbox\Desarrollo\workspace\python\chipas-windows\src\reportlab\platypus\flowables.py", line 408, in wrap return self.drawWidth, self.drawHeight File "C:\Users\Lucas\Dropbox\Desarrollo\workspace\python\chipas-windows\src\reportlab\platypus\flowables.py", line 402, in getattr self._setup_inner() File "C:\Users\Lucas\Dropbox\Desarrollo\workspace\python\chipas-windows\src\reportlab\platypus\flowables.py", line 368, in _setup_inner img = self._img File "C:\Users\Lucas\Dropbox\Desarrollo\workspace\python\chipas-windows\src\reportlab\platypus\flowables.py", line 398, in getattr self._img = ImageReader(self._file) File "C:\Users\Lucas\Dropbox\Desarrollo\workspace\python\chipas-windows\src\reportlab\lib\utils.py", line 541, in init if _isPILImage(fileName): File "C:\Users\Lucas\Dropbox\Desarrollo\workspace\python\chipas-windows\src\reportlab\lib\utils.py", line 521, in _isPILImage return isinstance(im,Image.Image) AttributeError: 'NoneType' object has no attribute 'Image' INFO 2012-02-29 19:54:37,276 dev_appserver.py:4247] "GET /pdf?pedido=ahVkZXZ-Y2hpcGFzLWludGhlY2xvdWRyLwsSBlBlZGlkbyIjMjAxMi0wMi0yOSAxOTo1NDoxOHRlc3RAZXhhbXBsZS5jb20M HTTP/1.1" 500 -

What's the proper way to add an image file inside a pdf document generated with reportlab? Many thanks in advance!

4条回答
我欲成王,谁敢阻挡
2楼-- · 2019-05-31 04:57

ReportLab requires PIL for images other than JPEG (PIL is not available on Appengine production), but it does support JPEG natively (see note below). So you need to provide ReportLab with JPEG images when rendering PDF files. With user-submitted images, I first use Appengine's API to transform the image to JPEG before rendering.

So step 1 is to change the logo from png to jpeg.

Secondly, Appengine does not allow you to read files from the static directory. It gives a 'File not Accessible' error if you try. Switch the .jpg to a directory other than /static/.

So whatever method you use to define the relative path to the file (gfortune's code works perfectly for this), to render the image, just use:

f = open(path_to_file, 'rb')

story.append( Image(f) )

Note: Several years ago, ReportLab had a bug where it would still try to access PIL, even for JPEG files. I corresponded with the developers, who provided a build that bypassed PIL for JPEG files. I'm not sure which build is the current build, so keep this in mind.

查看更多
迷人小祖宗
3楼-- · 2019-05-31 05:08

Try this simple function: This Worked For me....

def PrintImage(request):
    response = HttpResponse(content_type='application/pdf')
    doc = SimpleDocTemplate(response,topMargin=2)

    doc.pagesize = landscape(A6)
    elements = []
    I = Image('http://demoschoolzen.educationzen.com/images/tia.png')
    I.drawHeight =  0.7*inch
    I.drawWidth = 0.7*inch
    elements.append(I)
    doc.build(elements) 
    return response

and Call it from your URLs

查看更多
贪生不怕死
4楼-- · 2019-05-31 05:10

There are 2 ways this could be done.

If you are just working with a canvas:

canvas.drawInlineImage(APP_ROOT + "/static/footer_image.png", inch*.25, inch*.25, PAGE_WIDTH-(.5*inch), (.316*inch))

OR if you are using platypus and flowables

(answer taken from: http://www.tylerlesmann.com/2009/jan/28/writing-pdfs-python-adding-images/)

import os
import urllib2
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Image

filename = './python-logo.png'

def get_python_image():
    """ Get a python logo image for this example """
    if not os.path.exists(filename) :
        response = urllib2.urlopen('http://www.python.org/community/logos/python-logo.png')
        f = open(filename, 'w')
        f.write(response.read())
        f.close()

get_python_image()

doc = SimpleDocTemplate("image.pdf", pagesize=letter)
parts = []
parts.append(Image(filename))
doc.build(parts)
查看更多
戒情不戒烟
5楼-- · 2019-05-31 05:11

Main solution

It looks like the original error for this post is due to PIL maybe not being installed or perhaps a bug in an old version of PIL. See http://www.openerp.com/forum/topic18147.html for a similar situation. Try installing a recent version of PIL.

Also, see Appengine - Reportlab (Get Photo from Model) towards the end of the accepted solution and the comments.

Another potential problem in the code posted

Although this may not be directly related to the question asked, are you certain that im loaded correctly? Keep in mind that the path you've setup is relative to the directory from where the app was launched rather than relative to the current file. Use __file__ and some os.path trickery to make the path relative to chipas.py assuming that's the problem. If it's not the problem you're dealing with right now, it's certainly one you'll run into soon.

To reference a path relative to the directory of the current file, you would use something like:

Code

import os.path

def path_relative_to_file(base_file_path, relative_path):
    base_dir = os.path.dirname(os.path.abspath(base_file_path))
    return os.path.normpath(os.path.join(base_dir, relative_path))



print(__file__)
print(path_relative_to_file(__file__, '../static/logo.png'))


#Breaks if this code is run from a different directory
print(os.path.abspath('../static/logo.png'))

Output

gfortune@gfortune:/var/log$ python /home/gfortune/temp/temp.py
/home/gfortune/temp/temp.py
/home/gfortune/static/logo.png
/var/static/logo.png

Note that the path to '../static' works even though I launched the program from /var/log. Also note that blindly using ../static with abspath breaks if you run it from /var/log.

You can use that function as a little helper function by passing it __file__ from the module in question or you can just use the logic from it directly in chipas.py

查看更多
登录 后发表回答