Python 从PIL image或StringIO将图像插入Reportlab

Python 从PIL image或StringIO将图像插入Reportlab,python,python-imaging-library,reportlab,Python,Python Imaging Library,Reportlab,我正在尝试将条形码图像插入Reportlab。我知道在这方面有很多问题要问,但是所有问题都假定您已经在目录或文件系统中拥有映像文件 由于Reportlab与EAN13条形码存在问题,我决定使用另一个名为pyBarcode的包为我生成图像 最初,我将图像保存在一个StringIO实例中,并将其直接传递给reportlab.platypus.flowables.image,但这似乎不起作用。然后我阅读了文档: 支持PIL/Java1.4(Python/JavaImaging库)支持的格式 这是否意味

我正在尝试将条形码图像插入Reportlab。我知道在这方面有很多问题要问,但是所有问题都假定您已经在目录或文件系统中拥有映像文件

由于Reportlab与EAN13条形码存在问题,我决定使用另一个名为pyBarcode的包为我生成图像

最初,我将图像保存在一个StringIO实例中,并将其直接传递给
reportlab.platypus.flowables.image
,但这似乎不起作用。然后我阅读了文档:

支持PIL/Java1.4(Python/JavaImaging库)支持的格式

这是否意味着,如果我通过一个PIL图像,这应该工作?我尝试以下操作时出现异常:

>>> import PIL
>>> from reportlab.platypus.flowables import Image
>>> fp = StringIO(the_barcode.getvalue())
>>> barcode_image = PIL.Image.open(fp)
>>> doc = SimpleDocTemplate('barcode.pdf')
>>> story = [Image(barcode_image)]
>>> Traceback (most recent call last):
  File "create.py", line 57, in <module>
    main()
  File "create.py", line 24, in main
    save_pdf(fp, STYLE, ART, COLOR, SIZE)
  File "create.py", line 28, in save_pdf
    fp = StringIO(fp.getvalue())
  File "/home/mark/.virtualenvs/barcode/local/lib/python2.7/site-packages/reportlab-2.6-py2.7-linux-i686.egg/reportlab/platypus/flowables.py", line 402, in __init__
    if not fp and os.path.splitext(filename)[1] in ['.jpg', '.JPG', '.jpeg', '.JPEG']:
  File "/home/mark/.virtualenvs/barcode/lib/python2.7/posixpath.py", line 95, in splitext
    return genericpath._splitext(p, sep, altsep, extsep)
  File "/home/mark/.virtualenvs/barcode/lib/python2.7/genericpath.py", line 91, in _splitext
    sepIndex = p.rfind(sep)
  File "/home/mark/.virtualenvs/barcode/local/lib/python2.7/site-packages/PIL/Image.py", line 512, in __getattr__
    raise AttributeError(name)
AttributeError: rfind
导入PIL >>>从reportlab.platypus.flowables导入图像 >>>fp=StringIO(条形码.getvalue()) >>>条形码\图像=完整图像打开(fp) >>>doc=SimpleDoctTemplate('barcode.pdf') >>>故事=[图像(条形码图像)] >>>回溯(最近一次呼叫最后一次): 文件“create.py”,第57行,在 main() 文件“create.py”,第24行,在main中 保存pdf(fp、样式、艺术、颜色、大小) 保存pdf中的文件“create.py”,第28行 fp=StringIO(fp.getvalue()) 文件“/home/mark/.virtualenvs/barcode/local/lib/python2.7/site packages/reportlab-2.6-py2.7-linux-i686.egg/reportlab/platypus/flowables.py”,第402行,在__ 如果在['.jpg'、'.jpg'、'.jpeg'、'.jpeg']中没有fp和os.path.splitext(文件名)[1]: splitext中第95行的文件“/home/mark/.virtualenvs/barcode/lib/python2.7/posixpath.py” 返回genericpath.\u splitext(p,sep,altsep,extsep) 文件“/home/mark/.virtualenvs/barcode/lib/python2.7/genericpath.py”,第91行,在拆分文本中 sepIndex=p.rfind(sep) 文件“/home/mark/.virtualenvs/barcode/local/lib/python2.7/site packages/PIL/Image.py”,第512行,在__ 提升属性错误(名称) 属性错误:rfind
不知何故,PIL图像似乎也不起作用。如果我没有图像的文件名(因为我的图像是在内存中创建的),我应该将什么作为第一个参数传递给Reportlab的图像函数?

我相信PIL文档的意思是它在内部使用PIL来处理图像数据

从我在源代码中看到的情况来看,您可以直接传递文件对象,因此,使用
read()
方法:

我想你可以用某种方式将原始图像数据包装成一个类似文件的对象(StringIO或类似的)


编辑:我想这就是你以前做的,对不起。无论如何,这似乎是正确的方法。如果您告诉我们在这种情况下出现了什么问题,我们也许可以解决它。

重复声明“支持PIL/Java 1.4(Python/Java图像库)支持的格式”仅仅意味着
PIL
支持的数据格式受
reportlab
支持(因为它使用
PIL
读取它们)

现在,通过查看
reportlab.platypus.flowables.Image
code,可以看到它接受文件名或文件对象作为输入。前者不是你想要的,所以让我们关注后者。你说StringIO似乎不起作用,但如果你小心一点,它会起作用。您可能对它做了一些错误的操作,下面是使用
StringIO
的两种正确方法:

import sys
import PIL
from cStringIO import StringIO
from reportlab.platypus.flowables import Image

# Method 1
data = open(sys.argv[1]).read()
img1 = StringIO(data)

# Method 2
img2 = StringIO()
PIL.Image.open(sys.argv[2]).save(img2, 'PNG')
img2.seek(0)

# Method 3 (fails)
img3 = StringIO(PIL.Image.open(sys.argv[2]).tostring())

story = [Image(img1), Image(img2)]
#Image(img3)
方法3失败,因为
img3
现在保存图像的原始数据,因此它不知道该数据的实际格式。没有理由尝试将此方法用于此任务


如果您有原始数据,并且您知道数据的图像模式(“L”、“RGB”等)及其宽度和高度,那么您可以使用基于
PIL.image.fromstring(…).save(mystrio,'someformat')的第四种(正确)方法。
我对所建议的方法不太了解

检查pdfdoc.py中的代码表明,AttributeError是将StringIO作为文件名处理的结果:

    if source is None:
        pass # use the canned one.
    elif hasattr(source,'jpeg_fh'):
        self.loadImageFromSRC(source)   #it is already a PIL Image
    else:
        # it is a filename
进一步检查源代码,会发现jpeg_fh是reportlab.lib.utils中ImageReader类的一个属性。ImageReader同时接受StringIO和PIL图像

因此,在ImageReader中包装StringIO解决了我的问题:

import PIL
from reportlab.lib.utils import ImageReader

io_img = StringIO(data)
pil_img = PIL.Image.open(StringIO(data))

reportlab_io_img = ImageReader(io_img)
reportlab_pil_img = ImageReader(pil_img)

canvas.drawImage(reportlab_io_img, ...)
canvas.drawImage(reportlab_pil_img, ...)

在Python3中,使用“from io import BytesIO”而不是“from cStringIO import StringIO”。和“img2=BytesIO()”而不是“img2=StringIO()”
Image()
也可以采用来自
requests.get()
的“类似文件的响应对象表示法”。现在允许Image()filename参数可以是“类似文件的对象”。所以,呸,这不是一个未记录的特性。
Image(requests.get(“http://example.com/foo.png,stream=True)。例如,原始、w、h)