Python 使用pyfpdf将Base64图像插入pdf

Python 使用pyfpdf将Base64图像插入pdf,python,fpdf,Python,Fpdf,我在python中使用pyfpdf生成pdf文件。我有一个Base64,我想将它插入到pdf文件中,而不必将其保存为文件系统中的图像。但是pyfpdf image函数只接受文件路径 fpdf.image(name, x = None, y = None, w = 0, h = 0, type = '', link = '') 有没有一种方法(hack)可以直接从内存中插入base64或缓冲图像,而不必事先保存到文件系统中?我甚至在github上查看了他们的源代码,但还是不明白 链接:正如注释中

我在python中使用pyfpdf生成pdf文件。我有一个Base64,我想将它插入到pdf文件中,而不必将其保存为文件系统中的图像。但是pyfpdf image函数只接受文件路径

fpdf.image(name, x = None, y = None, w = 0, h = 0, type = '', link = '')
有没有一种方法(hack)可以直接从内存中插入base64或缓冲图像,而不必事先保存到文件系统中?我甚至在github上查看了他们的源代码,但还是不明白


链接:

正如注释中提到的@pvg一样,使用base64功能覆盖load\u资源功能可以实现这一点

import base64,io

def load_resource(self, reason, filename):
    if reason == "image":
        if filename.startswith("http://") or filename.startswith("https://"):
            f = BytesIO(urlopen(filename).read())
        elif filename.startswith("data"):
            f = filename.split('base64,')[1]
            f = base64.b64decode(f)
            f = io.BytesIO(f)
        else:
            f = open(filename, "rb")
        return f
    else:
        self.error("Unknown resource loading reason \"%s\"" % reason)
编辑:

这是将图像插入pdf的示例代码。我用代码注释了一些指令

from fpdf import FPDF
import os
import io
import base64


class PDF(FPDF):

    def load_resource(self, reason, filename):
        if reason == "image":
            if filename.startswith("http://") or filename.startswith("https://"):
                f = BytesIO(urlopen(filename).read())
            elif filename.startswith("data"):
                f = filename.split('base64,')[1]
                f = base64.b64decode(f)
                f = io.BytesIO(f)
            else:
                f = open(filename, "rb")
            return f
        else:
            self.error("Unknown resource loading reason \"%s\"" % reason)


    def sample_pdf(self,img,path):

        self.image(img,h=70,w=150,x=30,y=100,type="jpg")
        #make sure you use appropriate image format here jpg/png
        pdf.output(path, 'F')

if __name__ == '__main__':
    img = # pass your base64 image
    # you can find sample base64 here : https://pastebin.com/CaZJ7n6s

    pdf = PDF()
    pdf.add_page()
    pdf_path = # give path to where you want to save pdf
    pdf.sample_pdf(img,pdf_path) 

我最近一直在面对这个问题,而来自Uchiha Madara的答案在我的案例中不起作用,所以我用一种稍微不同的方式解决了这个问题。当我尝试使用Uchiha的方法时,我发现了与您在未对代码进行任何修改的情况下(未使用load_resource函数)提供图像时相同的FileNotFound错误。因为我真的需要一个解决方案,而且没有办法,所以我研究了可以在中找到的模块代码

C:/Users/user/AppData/Local/Programs/Python38/Lib/site-packages/fpdf/fpdf.py

如果您环顾四周,会发现图像是通过_parsepng函数导入的。因此,我们需要编辑它以接受base64数据字符串

基本上,您需要做什么来修复它:

在函数中,您需要在顶部添加一个elif,以检查“filename”是否包含指示其为base64的字符串,并且需要导入2个新模块

将此代码复制并粘贴到第一个if语句下面,以检查URL:

elif "data:image/png;base64" in name:
                f = name.split('base64,')[1]
                f = base64.b64decode(f)
                f = io.BytesIO(f)
这只是查找每个base64编码图像的典型字符串,如果它在那里,则对其进行解码

您需要导入脚本顶部的base64和io模块,因此只需通过

import base64, io
现在,只需像平常一样提供base64字符串作为文件路径,它就可以工作了(在我使用python 3.8进行的测试中)


如果您有任何问题,请与我联系,我希望我能在将来帮助一些人阅读本文

您可以子类化
fpdf
并覆盖
load\u resource
以返回
BytesIO
类似文件的对象。这是一个好主意。如果我被卡住了,你可以发布你的详细答案,这会对我有帮助。所有图像解析代码调用
load\u resource
,如果有不清楚的地方,去看看并问一个特定的问题。或者,您可能希望使用不同的pdf库进行探索,因为这一个看起来像是一个不洁的混乱(它是一个PHP端口)。我也觉得这个库出了问题,但它非常简单。您认为这在纯python环境中有效吗?还是我需要安装任何php依赖项?我想知道为什么“PHP端口”在这里是个问题。我正处于项目的早期阶段,所以您对它的看法将非常有帮助。我不知道,从我所看到的一点来看,它看起来像纯python。我所说的“PHP端口”是指有人将一些PHP代码转换成python。它似乎已经有一段时间没有维护了。另一方面,如果它起作用并且做了你想做的事情,你就会得到更多的力量。如果您还没有使用文件系统中的图像来测试它,那么您可能需要使用文件系统中的图像来测试它。在
if filename.startswith(“http://”)或filename.startswith(“https://”)块中,您需要将
f=BytesIO(…)
更改为
f=io.BytesIO(…)
。我也不确定urlopen(…)
属于哪个库。我的IDE显示它也无法确定这一点。这方面的修改会很好。非常感谢。对于发现此问题的任何其他人。此方法仅适用于开发版本fpdf。在编写本文时,pypi(1.7.2)上的版本以不同的方式处理加载图像。要使这个答案与pypi上的版本一起工作,您需要使用Github上主分支的代码重写FPDF.\u parsepng/jpg。