Appengine - Reportlab(从模型获取照片)
我正在使用Reportlab来生成PDF文件。 我无法从一个模型中获取照片。
#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))
当我创建PDF时,出现了这个错误:
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'
如果我把第419行注释掉,也就是调用照片的那一行,其他的就没问题了。 我已经在Datastore Viewer中检查过,模型是正常的。
有人能告诉我哪里出错了吗?
我应该用%s代替str吗?但是还是出现同样的错误。
1 个回答
根据ReportLab的API文档,drawImage()函数需要三个参数:'image, x, y',而你似乎传入的是'x, y, string'。
drawImage()的'image'参数需要一个文件名或者ImageReader对象。
根据这篇帖子,ImageReader的构造函数可以接受多种类型的参数。
更新:
在你发布的代码中,你把ImageReader赋值给了'image',但在调用drawImage时却传入了'imagem'(这个变量并不存在):
image = ImageReader(user.photo)
p.drawImage(imagem)
另外,user.photo是什么类型的模型属性?
更新 2:
你遇到的NoneType错误是因为user.photo是否是一个有效的blob,而不是None?
还有,blob是str的一个子类,但是ImageReader需要一个StringIO对象,所以我认为你需要把blob包装在StringIO中,然后传给ImageReader,比如:
import StringIO
image = ImageReader(StringIO.StringIO(user.photo))
p.drawImage(image)
顺便说一下,我猜测ImageReader('http://www.reportlab.com/rsrc/encryption.gif')
可能失败了,因为它可能试图从那个服务器加载图像,而使用了app engine不支持的API(也就是说,不是urlfetch)。
更新 3:
实际上,这看起来是ReportLab的一个bug。
我下载了ReportLab的2.4版本,在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):
ImageReader的构造函数调用_isPILImage来检查是否传入了PIL图像。然而PIL在app engine上不可用,所以Image是None,因此引用Image.Image时会抛出in _isPILImage AttributeError: 'NoneType' object has no attribute 'Image'.
这个错误。
我还发现了这篇博客,它描述了如何在使用ReportLab时处理图像。请查看“PDF中的图像”部分,了解如何解决这个问题,以及在app engine上运行时需要的其他修改。注意,博客中的行号似乎和我下载的2.4版本或你错误消息中的行号不匹配,所以请搜索提到的代码,而不是行号。
还要注意,没有PIL的ReportLab(即在app engine上运行时)只能绘制JPEG图像(这在那篇博客中也提到过)。
最后,在你发布的这段代码中:
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)
第一个问题是你调用drawImage时使用了'x, y, image',而参数应该是'image, x, y'。
其次,这里没有定义user或p(也许你把那部分代码删掉了?)。
第三,get()中为什么会有一个image参数?你在创建webapp.WSGIApplication()时是否从URL中解析出什么?如果没有,那么image将是None,这就是为什么什么都不会发生。
更新 4:
你现在遇到的Imaging Library not available, unable to import bitmaps only jpegs
错误是因为ReportLab无法读取JPEG以找到其宽度和高度。也许JPEG在你加载到blob时已损坏,或者JPEG的格式是ReportLab不支持的。
在ReportLab的lib\utils.py中,你可以暂时尝试更改以下内容(在2.5版本的第578行附近):
try:
self._width,self._height,c=readJPEGInfo(self.fp)
except:
raise RuntimeError('Imaging Library not available, unable to import bitmaps only jpegs')
改成这样:
self._width,self._height,c=readJPEGInfo(self.fp)
这样可以让你看到readJPEGInfo()
抛出的实际异常,这可能有助于找到问题的原因。
另一个可以尝试的方法是把你为用户上传的file.jpg放到你的项目中,然后做类似这样的操作:
imagem = canvas.ImageReader(StringIO.StringIO(open('file.jpg', 'rb').read()))
这将直接从文件加载JPEG,使用ImageReader,而不是从blob中加载。
如果这样有效,那么问题就是你的blob无效,所以你应该检查你的图像上传代码。如果失败,那么JPEG本身就是无效的(或者ReportLab不支持)。
更新 5:
你正在使用这个:
photo = images.resize(self.request.get('photo'), 32, 32)
根据这页上的resize文档,它有一个output_encoding参数,默认值是PNG。所以试试这个:
photo = images.resize(self.request.get('photo'), 32, 32, images.JPEG)