【问题标题】:Is there any way I can add image in bytes to pdf in Python?有什么方法可以在 Python 中以字节为单位将图像添加到 pdf 中?
【发布时间】:2018-11-11 03:17:08
【问题描述】:

我在 pandas 中生成了一些图并将其保存在 BytesIO 流中,然后我想将其添加到 pdf 页面,然后将 pdf 文件作为附件发送到电子邮件中:

import matplotlib.pyplot as plt
import io
from fpdf import FPDF

fig = plt.figure()
...
buf = io.BytesIO()
fig.savefig(buf, format='png')

pdf = FPDF()
pdf.add_page()
pdf.image(buf.getvalue(), type='PNG')
buf.close()

但这不起作用,报告以下错误:

Traceback (most recent call last):
  File "XXXX.py", line 166, in send_email
    pdf.image(buf.getvalue(), type='PNG')
  File "/usr/local/lib/python3.6/site-packages/fpdf/fpdf.py", line 150, in wrapper
    return fn(self, *args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/fpdf/fpdf.py", line 971, in image
    info=self._parsepng(name)
  File "/usr/local/lib/python3.6/site-packages/fpdf/fpdf.py", line 1769, in _parsepng
    if name.startswith("http://") or name.startswith("https://"):
TypeError: startswith first arg must be bytes or a tuple of bytes, not str

我想纯粹在内存中解决这个问题,而不是在本地保存图像文件。谁能帮我这个?非常感谢。

【问题讨论】:

  • image 方法需要一个“名称”(文件名或 URL),而不是 bytes

标签: python-3.x pandas matplotlib io fpdf


【解决方案1】:

“我想纯粹在内存中解决这个问题,而不是在本地保存图像文件。”

不,你不应该那样做。除非您将 PDF 保存在大容量内存文件驱动器的内存中。大多数设备使用文件系统来扩展内存,因此使用物理文件系统比在您非常宝贵的内存资源中构建自定义文件系统要容易得多。如果您的系统有一个内存流文件系统可以使用文件名,那么小文件可能会起作用。

PDF 是一种资源消耗,因为您必须这样做

  1. 将图像保存为自然压缩的图像对象
  2. 在那宝贵的内存中解压缩一个代表以一种或另一种方式作为 PDF 图像注入
  3. 通常被复制并重新展开以在屏幕上可见
  4. 那么需要将图像数据编码成一个放气的流对象
  5. 然后需要将新的平面图像作为部分文件对象写入 pdf,并在 PDF 文件系统中使用硬编码的十进制地址。
  6. 然后需要在物理文件的末尾对对象进行编目和索引,因此整个 PDF 也必须在内存中展开。

...我是在解释为什么只保存到滴灌缓存文件对象更简单吗?而不是乱用千兆字节的 RAM 驱动器。

【讨论】:

    【解决方案2】:

    是的,您可以使用字节代替文件...

    在我的例子中,我有一个包含图像作为二进制字符串的 MSSQL 查询。我想直接使用它们,而不保存多个图像文件。所以我一直在寻找解决方案。

    我们需要什么:

    pip install fpdf2
    

    然后将 IO 和 FPDF2 导入到你的 python 3.x 文件中:

    import io
    from fpdf import FPDF
    

    查看 Github 上 fpdf2-repository 的 image_parsing.py 表明 fpdf2 也可以处理二进制对象。不需要真正的图像文件。

    使用BytesIO from io,我们可以从我们的字节字符串中创建一个二进制对象。

    我们将二进制对象命名为“图片”并将其作为我们的图像放入 PDF 页面中。

    import io
    from fpdf import FPDF
    
    # create bytes object of the image data
    picture = io.BytesIO(b"some initial binary data: \x00\x01")
    
    # set page to portrait A4 and positioning in mm
    pdf = FPDF("P", "mm", "A4")
    
    # create a page
    pdf.add_page()
    
    # insert image
    # on position: x=10mm, y=10mm
    # size: width=50mm hight=auto
    pdf.image(picture,10,10,50)
    
    # create PDF file
    pdf.output("fpdf_test.pdf")
    

    我希望这对某些人有所帮助。

    【讨论】:

    • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
    猜你喜欢
    • 2015-09-25
    • 1970-01-01
    • 1970-01-01
    • 2015-03-01
    • 2013-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-30
    相关资源
    最近更新 更多