我正在尝试将几个 matplotlib 图形保存到使用 FPDF 创建的 PDF 中的特定位置。我不想将这些数字转储到文件中,然后将它们拉回。更好的解决方案似乎是将它们写入缓冲区,然后将它们读回,但我不确定这是否可能。
简化代码:
import pandas as pd
import matplotlib.pyplot as plt
from fpdf import FPDF
from io import BytesIO
import base64
# create figure
fig = plt.figure()
# add plot
ax = pd.Series( [1,3,2] ).plot()
# create bytesio object
bio = BytesIO()
# save figure to bytesio
fig.savefig(bio, format="png", bbox_inches='tight')
# this works to save the figure to a file
with open("myfile.png", "wb") as file:
file.write(bio.getvalue())
# create a PDF and set some attributes
pdf = FPDF(orientation="L", unit="in", format="letter")
pdf.set_font('Arial', 'B', 14)
pdf.add_page()
# try to read the bytesio object as though it's a file
# pdf.image() expects a file name or a URL: https://pyfpdf.readthedocs.io/en/latest/reference/image/index.html
# trying to create a data url with the base64-encoded data inside it
pdf.image( name='data://image/png;base64,' + base64.b64encode(bio.getvalue()).decode() , x=1, y=1, w=3.5, type='png')
# save pdf
pdf.output("mypdf.pdf")
完整的堆栈跟踪:
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
<ipython-input-17-0ec65d0f583e> in <module>()
30 # trying to create a data url with the base64-encoded data inside it
31
---> 32 pdf.image( name='data://image/png;base64,' + base64.b64encode(bio.getvalue()).decode() , x=1, y=1, w=3.5, type='png')
33
34 # save pdf
~\AppData\Local\Continuum\anaconda3\lib\site-packages\fpdf\fpdf.py in wrapper(self, *args, **kwargs)
148 self.error("No page open, you need to call add_page() first")
149 else:
--> 150 return fn(self, *args, **kwargs)
151 return wrapper
152
~\AppData\Local\Continuum\anaconda3\lib\site-packages\fpdf\fpdf.py in image(self, name, x, y, w, h, type, link)
969 info=self._parsejpg(name)
970 elif(type=='png'):
--> 971 info=self._parsepng(name)
972 else:
973 #Allow for additional formats
~\AppData\Local\Continuum\anaconda3\lib\site-packages\fpdf\fpdf.py in _parsepng(self, name)
1770 f = urlopen(name)
1771 else:
-> 1772 f=open(name,'rb')
1773 if(not f):
1774 self.error("Can't open image file: "+name)
FileNotFoundError: [Errno 2] No such file or directory: 'data://image/png;base64,iVBORw0KGgoAAAANSU #snipped for length#
由于 pdf.image() 可以采用 URL,因此我想构造一个实际上并不尝试打开文件的数据 URL。这就像在 HTML 页面中内嵌图像一样。就是这样的想法。我已经尝试了 getvalue() 、encode() 和decode() 的多次迭代,但没有得到正确的组合。
在本示例中,我成功写入文件以确保我的 BytesIO 对象中包含正确的数据,但将其转储到 pdf.image() 中不起作用。