views:

158

answers:

2

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.

A: 

Can somemone give feedback? Didn´t explained myself correctly? I can print to PDF an image that is inside my src(project), but can´t print an image from a model, that someone filled a form.

Is this a Reportlab issue?, or something with BlobProperty?

Martin
i think, in´m getting close to the solution. Trying with reportlab version 2.5, but still getting errors. File "C:\Users\hp\workspace\x-ray\src\principal.py", line 441, in post imagem = canvas.ImageReader(StringIO.StringIO(user.photo)) File "reportlab.zip\reportlab\lib\utils.py", line 588, in __init__ File "reportlab.zip\reportlab\lib\utils.py", line 582, in __init__RuntimeError: Imaging Library not available, unable to import bitmaps only jpegsfileName=<StringIO.StringIO instance at 0x04A5A030> identity=[ImageReader@0x4a62290].
Martin
After all the changes in utils.py, still buggy. image = canvas.ImageReader(StringIO.StringIO(user.photo)) File "reportlab.zip\reportlab\lib\utils.py", line 586, in __init__ File "reportlab.zip\reportlab\pdfbase\pdfutils.py", line 419, in readJPEGInfoPDFError: JPEG Unsupported JPEG marker: cf fileName=<StringIO.StringIO instance at 0x04811508>. note that i´ve uploaded more than one jpeg image and the error is always the same. Don´t believe that the file is corrupt.
Martin
@Martin: The cf marker in the error message indicates a rare type of lossless 'differential arithmetic' JPEG. If that is what you have used to compress your JPEGs, you should try using a standard JPEG compression format. If not, that suggests that the JPEG data in your blob has been corrupted. Did you try the ImageReader with the file, instead of the blob?
Saxon Druce
A: 

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)
Saxon Druce
Thanks Saxon, for your reply.I'll take a look at the link you sent me.It might be interesting and what I need. I´ll tell you then, if it worked or not
Martin
It throws an error: File "C:\Users\hp\workspace\myApp\src\principal.py", line 432, in post imagem = ImageReader('http://www.reportlab.com/rsrc/encryption.gif') File "reportlab.zip\reportlab\lib\utils.py", line 548, in __init__ File "reportlab.zip\reportlab\lib\utils.py", line 529, in _isPILImageAttributeError: 'NoneType' object has no attribute 'Image'
Martin
It throws an error: File "C:\Users\hp\workspace\myApp\src\principal.py", line 432, in post image = ImageReader(user.photo) File "reportlab.zip\reportlab\lib\utils.py", line 548, in __init__ File "reportlab.zip\reportlab\lib\utils.py", line 529, in _isPILImageAttributeError: 'NoneType' object has no attribute 'Image'. I tried this way image = ImageReader(user.photo) p.drawImage (imagem) . I´ve also tried instead of getting the model (user.photo), im=ImageReader('http://www.reportlab.com/rsrc/encryption.gif')c.drawImage(im), just like explained in your link
Martin
@Martin: I just updated my answer.
Saxon Druce
I know, this mistake ocurred, because i translated from portuguese to english. That´s why, but in code tha would give an error.
Martin
Class User: photo = db.BlobProperty()
Martin
@Martin: I've added another update.
Saxon Druce
Hi Saxon, keep throwing error. File "C:\Users\hp\workspace\myApp\src\principal.py", line 438, in post image = ImageReader(StringIO.StringIO(user.photo)) File "reportlab.zip\reportlab\lib\utils.py", line 548, in __init__ File "reportlab.zip\reportlab\lib\utils.py", line 529, in _isPILImageAttributeError: 'NoneType' object has no attribute 'Image'.
Martin
Then i added this line: 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). It doesn´t throw any error, but doesn´t show any image. Maybe the function isn´t correct. I´m newbie to Python.
Martin
@Martin: Looks like it's a bug in ReportLab - see my third update for details.
Saxon Druce
Hi Saxon, i changed the code to nick´s blog suggestion: image = canvas.ImageReader(StringIO.StringIO(user.photo)) p.drawImage(image, 40,700). Throws another error in utils.py File "C:\Users\hp\workspace\myApp\src\principal.py", line 441, in post image = canvas.ImageReader(StringIO.StringIO(user.photo)) File "reportlab.zip\reportlab\lib\utils.py", line 588, in __init__ RuntimeError: Imaging Library not available, unable to import bitmaps only jpegs fileName=<StringIO.StringIO instance at 0x04367B48>. Note that i uploaded a jpeg image.
Martin
@Martin: It sounds like you're doing everything right, so I'm not sure what the problem is. You might need to try debugging into ReportLab to figure out what's going wrong. You could also try the 2.5 version of ReportLab which was just released today, in case that works any better. Another thing to try would be to write a simple handler which writes out your user photo as a jpeg - so you can be sure that the jpeg has been loaded into the blob correctly.
Saxon Druce
@Martin: I've added another update with some things to try to debug the issue.
Saxon Druce
Hi, I´ve tested like you suggested. I´ve uploaded a pic to this site: http://tinypic.com/r/2ngeont/7. Take a look please. The image, also two images are loaded fine but when i try to load from the blob, throws errors. I don´t belive they´re corrupted or much compressed. The application should accept images from users with little restrictions. Do i have to make any function, handler to the blobProperty? Anyone have already this problem? Is there any samples to see the code?
Martin
@Martin: There is an example of how to upload a file into a blob here: http://code.google.com/appengine/docs/python/images/usingimages.html. Can you post the code you are using to upload your images?
Saxon Druce
class UploadFotoHandler(webapp.RequestHandler): def get(self): user = users.get_current_user() user = db.Query(models.User) user = user.filter('user =', user) users = user.fetch(limit = 1) self.response.headers['Content-Type'] = 'image/jpeg' for user in users: self.response.out.write(user.photo) An in UserHandler i use this: if data.is_valid(): if users.get_current_user(): user = users.get_current_user() if self.request.get('photo'): photo = images.resize(self.request.get('photo'), 32, 32) user.photo = db.Blob(photo) user.name = self.request.get('name')
Martin
@Martin: See my update - I think your images are being converted to PNG format when you resize them.
Saxon Druce
Hi Saxon, you´re the greatest. I could make it. I don´t know how to thank you. Thank you so much for your effort. Now I can do a job with better quality. Thanks so much.
Martin
No worries Martin, I'm glad we finally figured it out! :)
Saxon Druce