As @pvg mentioned in the comments, overriding load_resource function with your base64 functionality does the trick.
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. 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)
Answer from Uchiha Madara on Stack Overflowpython - Insert Base64 image to pdf using pyfpdf - Stack Overflow
How to use with Base64string PDF data
python - How to convert a pypdf reader object into a base64 string - Stack Overflow
ruby on rails - Convert base64 pdf string into an image - Stack Overflow
As @pvg mentioned in the comments, overriding load_resource function with your base64 functionality does the trick.
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. 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. 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 ). 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
If you look around there for a bit, you notice that the image is imported via the _parsepng function. So, we need to edit this to accept a base64 data string.
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.
Copy & paste this code below the first if-Statement to check for a 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.
You need to import the base64 and the io modules at the top of the script, so just do that via
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 ).
Contact me if you have any questions, I hope I can help some people reading this in the future.
In Imagemagick, you can do that with the INLINE: input structure. See http://www.imagemagick.org/Usage/files/#inline. For example:
convert 'inline:data:image/png;base64,
R0lGODlhIAAgAPIEAAAAAB6Q/76+vvXes////wAAAAAAAAAAACH5BAEAAAUALAAA
AAAgACAAAAOBWLrc/jDKCYG1NBcwegeaxHkeGD4j+Z1OWl4Yu6mAYAu1ebpwL/OE
YCDA0YWAQuJqRwsSeEyaRTUwTlxUqjUymmZpmeI3u62Mv+XWmUzBrpeit7YtB1/r
pTAefv942UcXVX9+MjNVfheGCl18i4ddjwwpPjEslFKDUWeRGj2fnw0JADs=
' b64_noseguy.png

file1 = Tempfile.new(['order', '.pdf'])
File.open(file1.path.to_s, 'wb') do |f|
f.write(Base64.decode64(label_string))
end
file = Tempfile.new(['order', '.png'])
im = Magick::Image.from_blob(open(file1.path.to_s).read).first
im.write(file.path.to_s)
pdf = Services::Invoices::Pdf.new(invoice).process(file.path)
file.unlink
pdf
This works, however; it does not seem like it would be the best solution.
If you don't want to use the xmlrpclib's Binary class, you can just use the .encode() method of strings:
a = open("pdf_reference.pdf", "rb").read().encode("base64")
Actually, after some more digging, it looks like the xmlrpclib module may have the piece I need with it's Binary helper class:
binary_obj = xmlrpclib.Binary( open('foo.pdf').read() )
Here's an example from the Trac XML-RPC documentation
import xmlrpclib
server = xmlrpclib.ServerProxy("http://athomas:password@localhost:8080/trunk/login/xmlrpc")
server.wiki.putAttachment('WikiStart/t.py', xmlrpclib.Binary(open('t.py').read()))
From my understanding base64decode only takes in a base64 string and looks like you have some headers on your string that are not encoded.
I would remove "data:application/pdf;base64,"
check out the doc here: https://docs.python.org/2/library/base64.html
When I've used it in the past, I have only used the encoded string.
Does writing it by using the codecs.decode function work?
also as Mark stated, you can try to remove the data:application/pdf;base64, portion of the string as this section of the string is not to be decoded.:
import codecs
base64String = "JVBERi0xLjQKJeHp69MKMSAwIG9iago8PC9Qcm9kdWNlciAoU2tpYS9..."
with open("test.pdf", "wb") as f:
f.write(codecs.decode(base64string, "base64"))