Appengine - Reportlab(从模型获取照片)

6 投票
1 回答
6773 浏览
提问于 2025-04-16 04:37

我正在使用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 个回答

13

根据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)

撰写回答