Generating PDFs from SVG input
Question:
I am trying to generate a PDF from a SVG input file with Python in a Django application.
I have already found 2 working solutions: cairo+rsvg and imagemagick but they both have one problem: They have some strange dependencies that I do not want to install on a server, for example DBUS and GTK.
So I am asking for another method for generating a PDF from SVG without having to install all these dependencies on a server.
Answers:
Have you considered svglib?
It looks quite promising, especially as reportlab is the featured pdf tool in Django’s docs.
from svglib.svglib import svg2rlg
from reportlab.graphics import renderPDF
drawing = svg2rlg("file.svg")
renderPDF.drawToFile(drawing, "file.pdf")
Yes, I would also suggest using svglib and the reportlab library for this task although there is very little documentation of the svglib library. I would actually suggest doing the following in your Django view:
from svglib.svglib import SvgRenderer
from reportlab.graphics import renderPDF
import xml.dom.minidom
@csrf_exempt
def export_svg(request):
# Get data from client side via POST variables
svg = request.POST.get("svg")
doc = xml.dom.minidom.parseString(svg.encode( "utf-8" ))
svg = doc.documentElement
# Create new instance of SvgRenderer class
svgRenderer = SvgRenderer()
svgRenderer.render(svg)
drawing = svgRenderer.finish()
# Instead of outputting to a file, we simple return
# the data and let the user download to their machine
pdf = renderPDF.drawToString(drawing)
response = HttpResponse(mimetype='application/pdf')
response.write(pdf)
# If one were to remove the 'attachment; ' from this line
# it would simple invoke the browsers default PDF plugin
response["Content-Disposition"]= "attachment; filename=converted.pdf"
return response
This way you never need to save a temporary file on the server for the user to just download locally anyway. The svglib example that is given requires providing a path to a file… but why not just provide the file itself?
I have documented the steps I have taken using Django and the Raphael SVG library here.
You will need to add “import string” for version 0.6.3 to work with python 2.7.
you can use my frok until the pypy is updated.
pip install git+git://github.com/ddehghan/libsvg.git
My answer may help someone on macOS:
I user CairoSVG
Firstly, install it with:
pip install cairosvg
Then you can use it in Python:
>>> import cairosvg
>>> cairosvg.svg2pdf(url='image.svg', write_to='image.pdf')
from its documentation:
on macOS, you’ll have to install cairo
and libffi
(with Homebrew for example)
As these answers are all quite old, I would like to post a modern solution using CairoSVG
This works with Django views:
import cairosvg
def export_svg(request):
# Get data from POST
svg = request.POST.get("svg")
pdf = cairosvg.svg2pdf(bytestring=svg.encode("utf-8"))
# The pdf is now a bytestring that can be returned instead of saving to disk.
response = HttpResponse(mimetype='application/pdf')
response.write(pdf)
I personally use pdfkit
wrapper for Wkhtmltopdf
.
I tested with your example of SVG and it does have opacity.
Though, to test – I’ve enclosed SVG file into HTML and then converted HTML to PDF.
You can give it a try on my server (which uses Wkhtmltopdf
):
response = requests.post('http://194.67.110.124:8000/html_to_pdf/',
files={
'template': ('template.html', open('template.html', 'rb')),
'picture': ('template.svg', open('template.svg', 'rb'))
},
data={})
where template.html is an HTML file contained SVG with prefix {{image_path}}
. For example:
<!DOCTYPE html>
<html lang="en">
<img src="{{image_path}}/template.svg">
</html>
and template.svg
if the SVG file. The result I get is:
The code for pdfkit is quite simple:
import pdfkit
pdfkit.from_file('template.html', 'output.pdf')
Where template.html
contains the embedded SVG.
Note that pdfkit
is only a wrapper and Wkhtmltopdf
app has to be installed on the machine. (BTW, on Windows it’s quite slow)
I am trying to generate a PDF from a SVG input file with Python in a Django application.
I have already found 2 working solutions: cairo+rsvg and imagemagick but they both have one problem: They have some strange dependencies that I do not want to install on a server, for example DBUS and GTK.
So I am asking for another method for generating a PDF from SVG without having to install all these dependencies on a server.
Have you considered svglib?
It looks quite promising, especially as reportlab is the featured pdf tool in Django’s docs.
from svglib.svglib import svg2rlg
from reportlab.graphics import renderPDF
drawing = svg2rlg("file.svg")
renderPDF.drawToFile(drawing, "file.pdf")
Yes, I would also suggest using svglib and the reportlab library for this task although there is very little documentation of the svglib library. I would actually suggest doing the following in your Django view:
from svglib.svglib import SvgRenderer
from reportlab.graphics import renderPDF
import xml.dom.minidom
@csrf_exempt
def export_svg(request):
# Get data from client side via POST variables
svg = request.POST.get("svg")
doc = xml.dom.minidom.parseString(svg.encode( "utf-8" ))
svg = doc.documentElement
# Create new instance of SvgRenderer class
svgRenderer = SvgRenderer()
svgRenderer.render(svg)
drawing = svgRenderer.finish()
# Instead of outputting to a file, we simple return
# the data and let the user download to their machine
pdf = renderPDF.drawToString(drawing)
response = HttpResponse(mimetype='application/pdf')
response.write(pdf)
# If one were to remove the 'attachment; ' from this line
# it would simple invoke the browsers default PDF plugin
response["Content-Disposition"]= "attachment; filename=converted.pdf"
return response
This way you never need to save a temporary file on the server for the user to just download locally anyway. The svglib example that is given requires providing a path to a file… but why not just provide the file itself?
I have documented the steps I have taken using Django and the Raphael SVG library here.
You will need to add “import string” for version 0.6.3 to work with python 2.7.
you can use my frok until the pypy is updated.
pip install git+git://github.com/ddehghan/libsvg.git
My answer may help someone on macOS:
I user CairoSVG
Firstly, install it with:
pip install cairosvg
Then you can use it in Python:
>>> import cairosvg
>>> cairosvg.svg2pdf(url='image.svg', write_to='image.pdf')
from its documentation:
on macOS, you’ll have to install
cairo
andlibffi
(with Homebrew for example)
As these answers are all quite old, I would like to post a modern solution using CairoSVG
This works with Django views:
import cairosvg
def export_svg(request):
# Get data from POST
svg = request.POST.get("svg")
pdf = cairosvg.svg2pdf(bytestring=svg.encode("utf-8"))
# The pdf is now a bytestring that can be returned instead of saving to disk.
response = HttpResponse(mimetype='application/pdf')
response.write(pdf)
I personally use pdfkit
wrapper for Wkhtmltopdf
.
I tested with your example of SVG and it does have opacity.
Though, to test – I’ve enclosed SVG file into HTML and then converted HTML to PDF.
You can give it a try on my server (which uses Wkhtmltopdf
):
response = requests.post('http://194.67.110.124:8000/html_to_pdf/',
files={
'template': ('template.html', open('template.html', 'rb')),
'picture': ('template.svg', open('template.svg', 'rb'))
},
data={})
where template.html is an HTML file contained SVG with prefix {{image_path}}
. For example:
<!DOCTYPE html>
<html lang="en">
<img src="{{image_path}}/template.svg">
</html>
and template.svg
if the SVG file. The result I get is:
The code for pdfkit is quite simple:
import pdfkit
pdfkit.from_file('template.html', 'output.pdf')
Where template.html
contains the embedded SVG.
Note that pdfkit
is only a wrapper and Wkhtmltopdf
app has to be installed on the machine. (BTW, on Windows it’s quite slow)