Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Appengine - Reportlab (Get Photo from Model)

I´m using Reportlab to generate a PDF. Can´t retrieve a photo from a model.

#Personal Info             
  p.drawImage('myPhoto.jpg', 40, 730)
  p.drawString(50, 670, 'Your name:' + '%s' % user.name)
  p.drawImage (50, 640, 'Photo: %s' % (user.photo))

When i create on generate PDF, i got this error:

Traceback (most recent call last):
  File "C:\Program Files (x86)\Google\google_appengine\google\appengine\ext\webapp\__init__.py", line 513, in __call__
    handler.post(*groups)
  File "C:\Users\hp\workspace\myApp\src\main.py", line 419, in post
    p.drawImage (50, 640, 'Photo: %s'  %                  (user.photo))
  File "reportlab.zip\reportlab\pdfgen\canvas.py", line 825, in drawImage
  File "reportlab.zip\reportlab\pdfbase\pdfdoc.py", line 2076, in __init__
  File "C:\Python25\lib\ntpath.py", line 189, in splitext
    i = p.rfind('.')
AttributeError: 'int' object has no attribute 'rfind'

If i comment the line which n.º 419, that calls the photo, everything goes fine. I´ve already inspected in Datastore Viewer and the models are ok.

Can someone point out what´s going wrong?

Should i use %s instead of str? But throws same error.

like image 478
Martinho Avatar asked Sep 26 '10 17:09

Martinho


1 Answers

According to the ReportLab API reference, drawImage() has arguments 'image, x, y', whereas it looks as though you are passing 'x, y, string'.

The image argument to drawImage() requires a filename or ImageReader.

According to this post, the ImageReader constructor can take several types of arguments.

Update:

In this code which you posted you are assigning the ImageReader to 'image', but passing 'imagem' (which doesn't exist) to drawImage:

image = ImageReader(user.photo) 
p.drawImage(imagem)

Also, what type of model property is user.photo?

Update 2:

You're getting an error about NoneType - are you sure user.photo is a valid blob, and not None?

Also, a blob is a subclass of str, but ImageReader requires a StringIO - so I think you need to wrap the blob in a StringIO to pass it to ImageReader, for example:

import StringIO
image = ImageReader(StringIO.StringIO(user.photo))
p.drawImage(image)

By the way, my guess is that ImageReader('http://www.reportlab.com/rsrc/encryption.gif') may have failed because it may be attempting to load the image from that server, using an API which app engine doesn't support (ie, not urlfetch).

Update 3:

Actually it looks like it's a bug in ReportLab.

I downloaded version 2.4 of ReportLab, and found this in utils.py:

def _isPILImage(im):
    try:
        return isinstance(im,Image.Image)
    except ImportError:
        return 0

class ImageReader(object):
    "Wraps up either PIL or Java to get data from bitmaps"
    _cache={}
    def __init__(self, fileName):
        ...
        if _isPILImage(fileName):

The ImageReader constructor calls _isPILImage to see if it was passed a PIL image. However PIL is not available on app engine, so Image is None, and therefore referencing Image.Image throws the in _isPILImage AttributeError: 'NoneType' object has no attribute 'Image'. which you are seeing.

I also found this blog post which describes how to use ReportLab with images. See the section 'Images in PDFs' for details on how to fix this issue, as well as another modification which is required to get it to work on app engine. Note that the line numbers in that blog post don't seem to match the 2.4 version which I downloaded, or the line numbers in your error messages - so search for the code mentioned, rather than the line numbers.

Also note that ReportLab without PIL (ie as it will run on app engine) can only draw JPEG images (as also mentioned in that blog post).

Finally, in this code you posted:

def get(self, image): 
    if image is not None: 
        image = ImageReader(StringIO.StringIO(user.photo)) 
        p.drawImage(40, 700, image) 
        p.setLineWidth(.3) 
        p.setFont('Helvetica', 10) 
        p.line(50, 660, 560, 660)

The first issue is that you are calling drawImage() with 'x, y, image', when the argments should be 'image, x, y'.

Secondly, neither user or p are defined here (maybe you cut out that code?).

Thirdly, why is there an image argument to get() - do you parse something out of the URL when you create the webapp.WSGIApplication()? If not, then image will be None, which is why nothing will happen.

Update 4:

The Imaging Library not available, unable to import bitmaps only jpegs error which you are now getting is because ReportLab is unable to read the jpeg to find its width and height. Maybe the jpeg was corrupted when you loaded it into the blob, or maybe the jpeg is in a format which ReportLab doesn't support.

In ReportLab's lib\utils.py, you could temporarily try changing the following (around line 578 of version 2.5):

try:
    self._width,self._height,c=readJPEGInfo(self.fp)
except:
    raise RuntimeError('Imaging Library not available, unable to import bitmaps only jpegs')

To just this:

self._width,self._height,c=readJPEGInfo(self.fp)

This will allow you to see the actual exception which readJPEGInfo() is throwing, which might help find the cause of the problem.

Another thing to try to help narrow down the problem might be to put the file.jpg which you uploaded for the user into your project, then do something like this:

imagem = canvas.ImageReader(StringIO.StringIO(open('file.jpg', 'rb').read()))

This will load the jpeg directly from the file, using the ImageReader, instead of from the blob.

If this works, then the problem is that your blob is invalid, so you should look at your image upload code. If it fails, then the jpeg itself is invalid (or unsupported by ReportLab).

Update 5:

You're using this:

photo = images.resize(self.request.get('photo'), 32, 32)

According to the documentation on resize on this page, it takes an output_encoding argument which defaults to PNG. So try this instead:

photo = images.resize(self.request.get('photo'), 32, 32, images.JPEG)
like image 177
Saxon Druce Avatar answered Sep 17 '22 11:09

Saxon Druce