从PIL图像或StringIO将图像插入到Reportlab中

时间:2012-12-19 13:40:10

标签: python python-imaging-library reportlab

我正在尝试将条形码图像插入到Reportlab中。我知道有很多问题要问这个,但是所有人都认为你已经在目录或文件系统中拥有了图像文件。

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

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

  

支持PIL / Java 1.4(Python / Java Imaging Library)支持的格式。

这是否意味着如果我传递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 Image似乎也无法正常工作。如果我没有图像的文件名(因为我的图像是在内存中创建的),我应该作为Reportlab的Image函数的第一个参数传递什么?

3 个答案:

答案 0 :(得分:11)

重复声明“支持PIL / Java 1.4支持的格式(Python / Java Imaging Library)”只是意味着PIL支持reportlab支持的数据格式(因为它使用{ {1}}阅读它们。)

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

StringIO

方法3失败,因为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) 现在保存图像的原始数据,因此它不知道该数据的实际格式。没有理由尝试将此方法用于此类任务。

如果您有原始数据并且您知道数据的图像模式('L','RGB'等)以及它的宽度,高度,那么您可以使用基于{{1的第四种(正确的)方法}}

答案 1 :(得分:11)

我对提出的方法没有好运。

检查pdfdoc.py中的代码,显示AttributError是将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图像。

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

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, ...)

答案 2 :(得分:0)

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

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

https://github.com/ejucovy/reportlab/blob/master/src/reportlab/platypus/flowables.py#L314

我想你可以以某种方式将原始图像数据包装在类似文件的对象(StringIO等)中。

编辑:我想这就是你以前做过的事,抱歉。无论如何,这似乎是正确的方式。也许如果你告诉我们在这种情况下有什么问题,我们将能够解决它。