簡體   English   中英

從 PIL 圖像或 StringIO 將圖像插入 Reportlab

[英]Insert image into Reportlab either from PIL image or StringIO

我正在嘗試將條形碼圖像插入 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 函數?

我對建議的方法沒有運氣。

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

重復聲明“支持 PIL/Java 1.4(Python/Java 圖像庫)支持的格式”只是意味着reportlab支持PIL支持的數據格式(因為它使用PIL來讀取它們)。

現在,通過查看reportlab.platypus.flowables.Image代碼,可以看到它接受文件名或文件對象作為輸入。 前者不是你想要的,所以讓我們關注后者。 你說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')

我相信 PIL 文檔的意思是它在內部使用 PIL 來處理圖像數據。

從我在源代碼中看到的,您可以直接傳遞文件對象,因此,使用read()方法:

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

我想你可以以某種方式將原始圖像數據包裝在一個類似文件的對象(StringIO 或類似的)中。

編輯:我想這就是你之前所做的,抱歉。 無論如何,這似乎是正確的方法。 也許如果你告訴我們在這種情況下有什么問題,我們就能解決它。

我發現兩種不同的模式很有用,這取決於我是在畫布上繪圖還是為 multiBuild 構建可流動的元素。 我正在使用保存到 BytesIO 緩沖區的 matplotlib 數字,但我假設相同的緩沖區將滿足您的條形碼需求。

對彼此而言:

import io

對於畫布:

from reportlab.lib.units import inch
from reportlab.lib.utils import ImageReader

# assume a proper Canvas object is instantiated as c

buf = io.BytesIO(the_barcode.getvalue())
buf.seek(0)
c.drawImage(ImageReader(buf), 0.5*inch, 5.5*inch, )

對於文檔的可流動元素:

from reportlab.platypus.flowables import Image

# assume story is a list of flowable elements for multiBuild

buf = io.BytesIO(the_barcode.getvalue())
buf.seek(0)
story.append(Image(buf))

經過多次試驗和錯誤,這些對我有用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM