简体   繁体   English

使用 pyfpdf 将 Base64 图像插入到 pdf

[英]Insert Base64 image to pdf using pyfpdf

I'm using pyfpdf in python to generate pdf files.我在python中使用pyfpdf生成pdf文件。 I have a Base64 which I want to insert into a pdf file without having to save it as an image in my file system.我有一个 Base64,我想将其插入到 pdf 文件中,而不必将其保存为文件系统中的图像。 But the pyfpdf image function only accepts file path.但是 pyfpdf 图像函数只接受文件路径。

fpdf.image(name, x = None, y = None, w = 0, h = 0, type = '', link = '')

Is there a way (hack) to directly insert base64 or buffered image from memory, without having to save into the file system beforehand?有没有办法(hack)直接从内存中插入 base64 或缓冲图像,而无需事先保存到文件系统中? I even checked their source code on github and couldn't figure.我什至在 github 上检查了他们的源代码,但无法弄清楚。

link : https://github.com/reingart/pyfpdf/tree/master/fpdf链接: https : //github.com/reingart/pyfpdf/tree/master/fpdf

As @pvg mentioned in the comments, overriding load_resource function with your base64 functionality does the trick.正如@pvg 在评论中提到的,使用 base64 功能覆盖 load_resource 函数可以解决问题。

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)

EDIT :编辑 :

This is a sample code to insert images into pdf.这是将图像插入 pdf 的示例代码。 I commented some instructions in code.我在代码中注释了一些说明。

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) 

I've been facing this issue lately and the answer from Uchiha Madara didn't work in my case, so I fixed it in a slightly different way.我最近一直在面对这个问题,而 Uchiha Madara 的回答在我的情况下不起作用,所以我以稍微不同的方式修复了它。 When I tried it with Uchiha's Method, I the same FileNotFound Error you do if you supply an image without any modification to your code ( without the load_resource function ).当我用 Uchiha 的方法尝试它时,如果您提供图像而不对代码进行任何修改(没有 load_resource 函数),我会遇到同样的 FileNotFound 错误。 Since I really needed a solution and there was no way around, I looked into the module code which can be found in由于我真的需要一个解决方案并且没有办法,我查看了可以在以下位置找到的模块代码

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

If you look around there for a bit, you notice that the image is imported via the _parsepng function.如果您环顾四周,您会注意到图像是通过 _parsepng 函数导入的。 So, we need to edit this to accept a base64 data string.因此,我们需要编辑它以接受 base64 数据字符串。

Basically, what you need to do to fix it:基本上,您需要做些什么来修复它:

In the function, you need to add an elif at the top to check whether the "filename" contains a string indicating it's base64, and you need to import 2 new modules.在函数中,需要在顶部添加一个elif来检查“filename”是否包含表示它是base64的字符串,并且需要导入2个新模块。

Copy & paste this code below the first if-Statement to check for a URL:将此代码复制并粘贴到第一个 if 语句下方以检查 URL:

elif "data:image/png;base64" in name:
                f = name.split('base64,')[1]
                f = base64.b64decode(f)
                f = io.BytesIO(f)

This just looks for the string which is typical for every base64-encoded image, and if it's there and decodes it.这只是查找每个 base64 编码图像的典型字符串,如果它在那里并对其进行解码。

You need to import the base64 and the io modules at the top of the script, so just do that via您需要在脚本顶部导入 base64 和 io 模块,因此只需通过

import base64, io

Now just supply your base64 string as the file path like you would do normally, and it should work ( did on my tests with python 3.8 ).现在只需像往常一样提供 base64 字符串作为文件路径,它应该可以工作(在我使用 python 3.8 的测试中完成)。

Contact me if you have any questions, I hope I can help some people reading this in the future.如果您有任何问题,请与我联系,我希望我可以帮助一些将来阅读本文的人。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM