Appengine - Reportlab (получить фото с модели) - PullRequest
5 голосов
/ 26 сентября 2010

Я использую 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 Ответ

12 голосов
/ 28 сентября 2010

Согласно справке ReportLab API , drawImage () имеет аргументы 'image, x, y', тогда как выглядит, как будто вы передаете 'x, y, string'.

Аргумент image для drawImage () требует имя файла или ImageReader.

Согласно этой записи , конструктор ImageReader может принимать несколько типов аргументов.

Обновление:

В этом коде, который вы разместили, вы назначаете ImageReader для 'image', но передаете 'imagem' (которого не существует) drawImage:

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') можетпроизошел сбой, поскольку он может пытаться загрузить изображение с этого сервера, используя API, который не поддерживается обработчиком приложений (т. е. не urlfetch ).

Обновление 3:

На самом деле похоже, что это ошибка в ReportLab.

Я скачал версию 2.4 ReportLab и нашел это в 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 недоступен в движке приложения, поэтому Image - None, и поэтому ссылка на Image.Image выбрасывает in _isPILImage AttributeError: 'NoneType' object has no attribute 'Image'., который вы видите.

Я также нашел это сообщение в блоге , которое описываеткак использовать ReportLab с изображениями.См. Раздел «Изображения в PDF-файлах» для получения подробной информации о том, как решить эту проблему, а также о других изменениях, необходимых для его работы на движке приложения.Обратите внимание, что номера строк в этом сообщении блога, похоже, не соответствуют версии 2.4, которую я скачал, или номерам строк в ваших сообщениях об ошибках - поэтому ищите упомянутый код, а не номера строк.

Также обратите внимание, что ReportLab без PIL (т. Е. Поскольку он будет работать на движке приложения) может рисовать только изображения в формате 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'.

Во-вторых, ни пользователь, ни p не являютсяопределено здесь (может быть, вы вырезали этот код?).

В-третьих, почему есть аргумент image для get () - вы анализируете что-то из URL при создании webapp.WSGIApplication ()?Если нет, то изображение будет Нет, поэтому ничего не произойдет.

Обновление 4:

Ошибка Imaging Library not available, unable to import bitmaps only jpegs, которую вы сейчас получаете, связана с тем, что ReportLabне может прочитать JPEG, чтобы найти его ширину и высоту.Возможно, jpeg был поврежден при загрузке его в большой двоичный объект, или, возможно, jpeg находится в формате, который ReportLab не поддерживает.

В lib \ utils.py в ReportLab вы можете временно попытаться изменить следующее (вокруг строки 578 версии 2.5):

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(), что может помочь найтипричина проблемы.

Еще одна попытка помочь сузить проблему - поместить файл.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)

В соответствии с документацией по изменению размера на этой странице, он принимает аргумент output_encoding, который по умолчанию равен PNG. Попробуйте вместо этого:

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