Convert SVG to PNG in Python
Asked Answered
M

16

165

How do I convert an svg to png, in Python? I am storing the svg in an instance of StringIO. Should I use the pyCairo library? How do I write that code?

Megagamete answered 5/7, 2011 at 21:59 Comment(7)
Possibly a duplicate of #2932908Densmore
That thread left the problem unsolved. The accepted answer came from the asker who was sharing his failed code attempt. The other answer suggested ImageMagick but a commenter said ImageMagick does "a horrible job of interpreting SVG." I don't want my pngs to look horrible so I'm re-asking the question.Megagamete
Try cairographics.org/cookbook/librsvgpythonDensmore
The examples in that link are specific to Win32. I'm running linux.Megagamete
Take a look at this blog post, it looks like it might be what you need.Investigate
Simple SVGs: github.com/aslpavel/svgrasterize.pyRiggins
Does this answer your question? Server-side SVG to PNG (or some other image format) in pythonHonig
P
74

The answer is "pyrsvg" - a Python binding for librsvg.

There is an Ubuntu python-rsvg package providing it. Searching Google for its name is poor because its source code seems to be contained inside the "gnome-python-desktop" Gnome project GIT repository.

I made a minimalist "hello world" that renders SVG to a cairo surface and writes it to disk:

import cairo
import rsvg

img = cairo.ImageSurface(cairo.FORMAT_ARGB32, 640,480)

ctx = cairo.Context(img)

## handle = rsvg.Handle(<svg filename>)
# or, for in memory SVG data:
handle= rsvg.Handle(None, str(<svg data>))

handle.render_cairo(ctx)

img.write_to_png("svg.png")

Update: as of 2014 the needed package for Fedora Linux distribution is: gnome-python2-rsvg. The above snippet listing still works as-is.

Purveyance answered 6/7, 2011 at 15:40 Comment(8)
Great, works nicely. But is there a way to let cairo determine the HEIGHT and WIDTH of the picture on its own? I've looked into the *.svg file, to extract the HEIGHT and WIDTH from there, but it is both set to 100%. Of course, I can look into the properties of the picture, but since this is only one step in image processing this is not what I want.Adkinson
If the "width" and "height" of your files are set to 100%, there is no magic Cairo or rsvg can do to guess the size: such SVG files were left size independent by the creator software(/person). The surrounding HTML code to import the SVG file would supply the physical size. However, the "Handle" object of rsvg do have a .get_dimension_data() method that worked for my example file (a well behaved SVG) - give it a try.Purveyance
as of 2014, for ubuntu, you can use: apt-get install python-rsvgGaultheria
Is there a quick command for adding a white background to the image if its current background is transparent?Ayo
@Purveyance I use Windows 8.1 and python 2.7.11 How can I install cairo and rsvg and make it work. I was struggling to make this work. BTW +1 for your detailed explanation.Sophy
@MarlonAbeykoon: I think it is better you ask this as a separate question on another Stack Exchange forum - (I actually have no idea). Likely superuser.com is your best choice. Just put a link to this question on your question there to give some more context to whoever knows how to answer this.Purveyance
I used bit old version of wand to do it. Since latest version had some issuesSophy
The pyrsvg link is dead.Hypothetical
S
148

Here is what I did using cairosvg:

from cairosvg import svg2png

svg_code = """
    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
        <circle cx="12" cy="12" r="10"/>
        <line x1="12" y1="8" x2="12" y2="12"/>
        <line x1="12" y1="16" x2="12" y2="16"/>
    </svg>
"""

svg2png(bytestring=svg_code,write_to='output.png')

And it works like a charm!

See more: cairosvg document

Solid answered 10/11, 2012 at 8:20 Comment(11)
Hi. Do you know how can i do the same but without writing to a file? I need to push png content to the browser from a webserver, so that way the user can download the image. Saving the png file is not a valid option in our project, that's why I need it that way. ThanksChromate
I've been doing this myself. It basically depends on what tools or frameworks u have at hand when handling your web requests, but no matter what it is, the basic idea is that svg2png takes in a stream object in the write_to parameter, and this can either be your HTTP Response object (which in most frameworks is a file-like object) or some other stream, which you then serve to the browser using the Content-Disposition header. see here: #1012937Solid
For those who experiences the issues with that code, as I was: 1). bytestring accepts bytes, so convert string first with bytestring=bytes(svg,'UTF-8') 2). file mode should be binary, so open('output.png','wb')Apartment
The equivalent of @SerjZaharchenko's answer for Python 2.x is bytestring=svg.encode('utf-8')Celia
If you want to set the width and height with cairosvg, the SVG must have a viewbox. You can add one using scour.Papke
cairosvg supports only Python 3.4+. They have dropped Python 2 supportSophy
Note that for python 2.7 you need to pip install cairosvg==1.0.22 , otherwise you'll have installation issues.Softshoe
There wasn't a svg2png for me, I had to use cairosvg.surface.PNGSurface.convert(svg_str, write_to='output.png').Hbeam
@Chromate if you pass write_to=None it returns a bytestring.Lyte
@Chromate Yes; here's how to do that: PIL.Image.open(io.BytesIO(cairosvg.svg2png(url=filename, write_to=None)))Volatile
If you have problems getting CairoSVG running on windows, see this solution: https://mcmap.net/q/48557/-convert-svg-to-png-with-python-on-windowsRhodesia
P
74

The answer is "pyrsvg" - a Python binding for librsvg.

There is an Ubuntu python-rsvg package providing it. Searching Google for its name is poor because its source code seems to be contained inside the "gnome-python-desktop" Gnome project GIT repository.

I made a minimalist "hello world" that renders SVG to a cairo surface and writes it to disk:

import cairo
import rsvg

img = cairo.ImageSurface(cairo.FORMAT_ARGB32, 640,480)

ctx = cairo.Context(img)

## handle = rsvg.Handle(<svg filename>)
# or, for in memory SVG data:
handle= rsvg.Handle(None, str(<svg data>))

handle.render_cairo(ctx)

img.write_to_png("svg.png")

Update: as of 2014 the needed package for Fedora Linux distribution is: gnome-python2-rsvg. The above snippet listing still works as-is.

Purveyance answered 6/7, 2011 at 15:40 Comment(8)
Great, works nicely. But is there a way to let cairo determine the HEIGHT and WIDTH of the picture on its own? I've looked into the *.svg file, to extract the HEIGHT and WIDTH from there, but it is both set to 100%. Of course, I can look into the properties of the picture, but since this is only one step in image processing this is not what I want.Adkinson
If the "width" and "height" of your files are set to 100%, there is no magic Cairo or rsvg can do to guess the size: such SVG files were left size independent by the creator software(/person). The surrounding HTML code to import the SVG file would supply the physical size. However, the "Handle" object of rsvg do have a .get_dimension_data() method that worked for my example file (a well behaved SVG) - give it a try.Purveyance
as of 2014, for ubuntu, you can use: apt-get install python-rsvgGaultheria
Is there a quick command for adding a white background to the image if its current background is transparent?Ayo
@Purveyance I use Windows 8.1 and python 2.7.11 How can I install cairo and rsvg and make it work. I was struggling to make this work. BTW +1 for your detailed explanation.Sophy
@MarlonAbeykoon: I think it is better you ask this as a separate question on another Stack Exchange forum - (I actually have no idea). Likely superuser.com is your best choice. Just put a link to this question on your question there to give some more context to whoever knows how to answer this.Purveyance
I used bit old version of wand to do it. Since latest version had some issuesSophy
The pyrsvg link is dead.Hypothetical
I
50

Install Inkscape and call it as command line:

${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -j -e ${dest_png}

You can also snap specific rectangular area only using parameter -j, e.g. co-ordinate "0:125:451:217"

${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -j -a ${coordinates} -e ${dest_png}

If you want to show only one object in the SVG file, you can specify the parameter -i with the object id that you have setup in the SVG. It hides everything else.

${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -i ${object} -j -a ${coordinates} -e ${dest_png}
Innumerable answered 12/4, 2012 at 19:1 Comment(3)
+1 because this is also extremely handy for shell scripting. See inkscape.org/doc/inkscape-man.html for full docs on Inkscape's command line.Westerfield
Thanks, this was the easiest way I found to do this. On Windows, to make it so that you don't have to type in the full path to Inkscape every time, you can add it to your Path in Environmental Variables.Bugbee
This is not an answer. It's a workaround. OP asked for a Python solution.Footpad
W
36

I'm using Wand-py (an implementation of the Wand wrapper around ImageMagick) to import some pretty advanced SVGs and so far have seen great results! This is all the code it takes:

    with wand.image.Image( blob=svg_file.read(), format="svg" ) as image:
        png_image = image.make_blob("png")

I just discovered this today, and felt like it was worth sharing for anyone else who might straggle across this answer as it's been a while since most of these questions were answered.

NOTE: Technically in testing I discovered you don't even actually have to pass in the format parameter for ImageMagick, so with wand.image.Image( blob=svg_file.read() ) as image: was all that was really needed.

EDIT: From an attempted edit by qris, here's some helpful code that lets you use ImageMagick with an SVG that has a transparent background:

from wand.api import library
import wand.color
import wand.image

with wand.image.Image() as image:
    with wand.color.Color('transparent') as background_color:
        library.MagickSetBackgroundColor(image.wand, 
                                         background_color.resource) 
    image.read(blob=svg_file.read(), format="svg")
    png_image = image.make_blob("png32")

with open(output_filename, "wb") as out:
    out.write(png_image)
Wiltshire answered 31/10, 2013 at 23:7 Comment(11)
Wand worked a lot better than Cairo for my PNGs.Gliwice
Thanks @Gliwice - added your transparent background SVG rendering code to my answer as well.Wiltshire
this looks nice, but where do you put the svg's filename??Sensory
I get the error image.read(blob=svg_file.read(), format="svg") NameError: name 'svg_file' is not definedSensory
svg_file is assumed to be a "file" object in this example, setting svg_file would look something like: svg_file = File.open(file_name, "r")Wiltshire
Thanks, the cairo and rsvg 'accepted' method didn't work for my PDF. pip install wand and your snippet did the trick ;)Rosenberg
If you have an svg str then you first need to encode into binary like this: svg_blob = svg_str.encode('utf-8'). Now you can use the method above by replacing blob=svg_file.read() with blob=svg_blob.Pico
This still didn't export correctly with fonts... I know that's not helpful... so specifically, I have an svg that utilizes the font-family property and loads all of the fonts from external stylesheets generated by font squirrel . com ...Rugged
FYI, i had trouble directly running the above code. First thing is that i had to install potrace from bioconda. Second, i actually end up using this svg_to_png function from programcreek.com/python/… -- i hope it will be helpful for someone else tooBoleslaw
With Wand 0.6.6 in MacOs, png_image was always None, make it works by adding background in constructor too: image.read(blob=svg_file.read(), background=background_color), format="svg")Caudex
FYI, this solution requires both Imagemagick and Inkscape to be installed.Macnamara
E
30

I did not find any of the answers satisfactory. All the mentioned libraries have some problem or the other like Cairo dropping support for python 3.6 (they dropped Python 2 support some 3 years ago!). Also, installing the mentioned libraries on the Mac was a pain.

Finally, I found the best solution was svglib + reportlab. Both installed without a hitch using pip and first call to convert from svg to png worked beautifully! Very happy with the solution.

Just 2 commands do the trick:

from svglib.svglib import svg2rlg
from reportlab.graphics import renderPM
drawing = svg2rlg("my.svg")
renderPM.drawToFile(drawing, "my.png", fmt="PNG")

Are there any limitations with these I should be aware of?

Egbert answered 27/12, 2019 at 19:26 Comment(7)
Yes, marker-end is not supported, and won't be, github.com/deeplook/svglib/issues/177Opulence
Great solution for those that work on Windows, absolutely no dependencies required at SO level. Thanks!!Dewey
In case you need to continue some operations with PIL pil_img = renderPM.drawToPILP(drawing)Maestoso
Looks great, but svglib doesn't install properly via pip on Termux (the above answers don't seem to work on Termux, either, though).Macnamara
In case you stumble over background transparency or scaling issues but don't want any external dependencies, check out my workaround belowUpbringing
I tried your code but it says: 'NoneType' object has no attribute 'renderScale'Barra
I tried this solution and get the following on windows : ModuleNotFoundError: No module named 'rlPyCairo'Henbit
V
13

Try this: http://cairosvg.org/

The site says:

CairoSVG is written in pure python and only depends on Pycairo. It is known to work on Python 2.6 and 2.7.

Update November 25, 2016:

2.0.0 is a new major version, its changelog includes:

  • Drop Python 2 support
Violaviolable answered 22/7, 2011 at 13:30 Comment(5)
There is two problem with this, unfortunately. First, it doesn't handle the <clipPath><rect ... /></clipPath>. Second, it doesn't take the -d (DPI) option.Wellmannered
@Wellmannered , please send bug reports / feature requests on the CairoSVG tracker!Grape
@Simon, Can you do it please? I'm too busy and I will be in the next 1-2 month.Wellmannered
@Ray, actually the -d / --dpi option has been there for a while now, and I’m told that support for <clippath> was added a few weeks back in the git version.Grape
I had some problems with SVGs that use opacity. In my case Wand-py showed to be a better solution.Kimmy
L
9

Another solution I've just found here How to render a scaled SVG to a QImage?

from PySide.QtSvg import *
from PySide.QtGui import *


def convertSvgToPng(svgFilepath,pngFilepath,width):
    r=QSvgRenderer(svgFilepath)
    height=r.defaultSize().height()*width/r.defaultSize().width()
    i=QImage(width,height,QImage.Format_ARGB32)
    p=QPainter(i)
    r.render(p)
    i.save(pngFilepath)
    p.end()

PySide is easily installed from a binary package in Windows (and I use it for other things so is easy for me).

However, I noticed a few problems when converting country flags from Wikimedia, so perhaps not the most robust svg parser/renderer.

Luminescence answered 15/4, 2014 at 20:5 Comment(0)
D
8

Here is a another solution without using rsvg(which is currently not available for windows).Only install cairosvg using pip install CairoSVG

svg2png.py

from cairosvg import svg2png
svg_code = open("input.svg", 'rt').read()
svg2png(bytestring=svg_code,write_to='output.png')
Dungdungan answered 27/5, 2021 at 9:29 Comment(1)
Another simpler way: cairosvg.svg2png(url="/path/to/input.svg", write_to="/tmp/output.png"). As shared in Cairosvg's official documentation: cairosvg.org/documentationBoonie
A
6

A little extension on the answer of jsbueno:

#!/usr/bin/env python

import cairo
import rsvg
from xml.dom import minidom


def convert_svg_to_png(svg_file, output_file):
    # Get the svg files content
    with open(svg_file) as f:
        svg_data = f.read()

    # Get the width / height inside of the SVG
    doc = minidom.parse(svg_file)
    width = int([path.getAttribute('width') for path
                 in doc.getElementsByTagName('svg')][0])
    height = int([path.getAttribute('height') for path
                  in doc.getElementsByTagName('svg')][0])
    doc.unlink()

    # create the png
    img = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
    ctx = cairo.Context(img)
    handler = rsvg.Handle(None, str(svg_data))
    handler.render_cairo(ctx)
    img.write_to_png(output_file)

if __name__ == '__main__':
    from argparse import ArgumentParser

    parser = ArgumentParser()

    parser.add_argument("-f", "--file", dest="svg_file",
                        help="SVG input file", metavar="FILE")
    parser.add_argument("-o", "--output", dest="output", default="svg.png",
                        help="PNG output file", metavar="FILE")
    args = parser.parse_args()

    convert_svg_to_png(args.svg_file, args.output)
Alkmaar answered 11/6, 2014 at 17:43 Comment(1)
I used the svg width and height extraction. I'm not sure about the svg standard but in some of my svg files the width or height were followed by a non numeric string such as 'mm' or 'px' (ex: '250mm'). The int('250mm') throws an exception and I had to make some additional tweaks.Kemberlykemble
L
3

Here is an approach where Inkscape is called by Python.

Note that it suppresses certain crufty output that Inkscape writes to the console (specifically, stderr and stdout) during normal error-free operation. The output is captured in two string variables, out and err.

import subprocess               # May want to use subprocess32 instead

cmd_list = [ '/full/path/to/inkscape', '-z', 
             '--export-png', '/path/to/output.png',
             '--export-width', 100,
             '--export-height', 100,
             '/path/to/input.svg' ]

# Invoke the command.  Divert output that normally goes to stdout or stderr.
p = subprocess.Popen( cmd_list, stdout=subprocess.PIPE, stderr=subprocess.PIPE )

# Below, < out > and < err > are strings or < None >, derived from stdout and stderr.
out, err = p.communicate()      # Waits for process to terminate

# Maybe do something with stdout output that is in < out >
# Maybe do something with stderr output that is in < err >

if p.returncode:
    raise Exception( 'Inkscape error: ' + (err or '?')  )

For example, when running a particular job on my Mac OS system, out ended up being:

Background RRGGBBAA: ffffff00
Area 0:0:339:339 exported to 100 x 100 pixels (72.4584 dpi)
Bitmap saved as: /path/to/output.png

(The input svg file had a size of 339 by 339 pixels.)

Legman answered 5/10, 2017 at 16:36 Comment(2)
It's not end-to-end Python if you rely on Inkscape.Aun
@Joel: First line has been modified to overcome your objection. But of course, even a "pure" Python solution relies on elements outside the core language, and is ultimately run with machine language, so perhaps there is no such thing as end-to-end anything!Legman
B
3

SVG scaling and PNG rendering

Using pycairo and librsvg I was able to achieve SVG scaling and rendering to a bitmap. Assuming your SVG is not exactly 256x256 pixels, the desired output, you can read in the SVG to a Cairo context using rsvg and then scale it and write to a PNG.

main.py

import cairo
import rsvg

width = 256
height = 256

svg = rsvg.Handle('cool.svg')
unscaled_width = svg.props.width
unscaled_height = svg.props.height

svg_surface = cairo.SVGSurface(None, width, height)
svg_context = cairo.Context(svg_surface)
svg_context.save()
svg_context.scale(width/unscaled_width, height/unscaled_height)
svg.render_cairo(svg_context)
svg_context.restore()

svg_surface.write_to_png('cool.png')

RSVG C binding

From the Cario website with some minor modification. Also a good example of how to call a C-library from Python

from ctypes import CDLL, POINTER, Structure, byref, util
from ctypes import c_bool, c_byte, c_void_p, c_int, c_double, c_uint32, c_char_p


class _PycairoContext(Structure):
    _fields_ = [("PyObject_HEAD", c_byte * object.__basicsize__),
                ("ctx", c_void_p),
                ("base", c_void_p)]


class _RsvgProps(Structure):
    _fields_ = [("width", c_int), ("height", c_int),
                ("em", c_double), ("ex", c_double)]


class _GError(Structure):
    _fields_ = [("domain", c_uint32), ("code", c_int), ("message", c_char_p)]


def _load_rsvg(rsvg_lib_path=None, gobject_lib_path=None):
    if rsvg_lib_path is None:
        rsvg_lib_path = util.find_library('rsvg-2')
    if gobject_lib_path is None:
        gobject_lib_path = util.find_library('gobject-2.0')
    l = CDLL(rsvg_lib_path)
    g = CDLL(gobject_lib_path)
    g.g_type_init()

    l.rsvg_handle_new_from_file.argtypes = [c_char_p, POINTER(POINTER(_GError))]
    l.rsvg_handle_new_from_file.restype = c_void_p
    l.rsvg_handle_render_cairo.argtypes = [c_void_p, c_void_p]
    l.rsvg_handle_render_cairo.restype = c_bool
    l.rsvg_handle_get_dimensions.argtypes = [c_void_p, POINTER(_RsvgProps)]

    return l


_librsvg = _load_rsvg()


class Handle(object):
    def __init__(self, path):
        lib = _librsvg
        err = POINTER(_GError)()
        self.handle = lib.rsvg_handle_new_from_file(path.encode(), byref(err))
        if self.handle is None:
            gerr = err.contents
            raise Exception(gerr.message)
        self.props = _RsvgProps()
        lib.rsvg_handle_get_dimensions(self.handle, byref(self.props))

    def get_dimension_data(self):
        svgDim = self.RsvgDimensionData()
        _librsvg.rsvg_handle_get_dimensions(self.handle, byref(svgDim))
        return (svgDim.width, svgDim.height)

    def render_cairo(self, ctx):
        """Returns True is drawing succeeded."""
        z = _PycairoContext.from_address(id(ctx))
        return _librsvg.rsvg_handle_render_cairo(self.handle, z.ctx)
Bolyard answered 22/4, 2018 at 9:28 Comment(2)
Thanks for this, it proved very useful in a project of mine. Although Handle.get_dimension_data didn't work for me. I had to replace it with a simple fetching of self.props.width and self.props.height. I first tried defining the RsvgDimensionData Structure as described on the cairo website, but without success.Arissa
I am trying to use this in a project of mine. How do I obtain the dll files required?Lourdeslourie
C
3

Try this python script:

Don't forget to install cairosvg: pip3 install cairosvg

#!/usr/bin/env python3
import os
import cairosvg

for file in os.listdir('.'):
    if os.path.isfile(file) and file.endswith(".svg"):
        name = file.split('.svg')[0]
        cairosvg.svg2png(url=name+'.svg',write_to=name+'.png')

Christiachristian answered 15/12, 2021 at 2:26 Comment(1)
For an anaconda distribution use conda install -c conda-forge cairosvg rather than pip3 install cairosvg or the install will not work correctly. This works phenomenally for windows.Steamship
U
2

Posting my code from this StackOverflow answer. It's a workaround to svglib+reportlib not supporting a transparent background and no scaling (see @sarang's answer and @ualter-jr's answer as well as these Github issues on scaling not working and this one on transparency)

This uses pyMuPDF to render an intermediate pdf from reportlab to PNG.

The big advantage is that it doesn't need any external libraries as pymupdf comes with precompiled wheels for Windows, Linux and MacOS.

The whole thing is as easy as

pip install pymupdf svglib

and then executing the following lines

import fitz
from svglib import svglib
from reportlab.graphics import renderPDF

# Convert svg to pdf in memory with svglib+reportlab
# directly rendering to png does not support transparency nor scaling
drawing = svglib.svg2rlg(path="input.svg")
pdf = renderPDF.drawToString(drawing)

# Open pdf with fitz (pyMuPdf) to convert to PNG
doc = fitz.Document(stream=pdf)
pix = doc.load_page(0).get_pixmap(alpha=True, dpi=300)
pix.save("output.png")
Upbringing answered 22/10, 2022 at 16:7 Comment(1)
No other solution worked without installing any dependencies. Thanks so much!Dulse
C
1

Try using Gtk.Image and Gdk.Pixbuf

import gi
gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0')

from gi.repository import Gdk, Gtk
from PIL import Image

image = Gtk.Image()
image.set_from_file("path/to/image.svg")
pb = image.get_pixbuf()
pb.savev("path/to/convented/image.jpeg","jpeg",[],[])
im = Image.open("path/to/convented/image.jpeg")
pix = im.load()
print(pix[1,1])
Carrycarryall answered 9/1, 2022 at 11:18 Comment(2)
I am sure it would help the community if you explained to us why and how you code would solve the OP's problemEllerey
This works with SVG files that are not correctly rendered by Cairo, Inkspace but are correctly rendered by Gimp and Image Viewer.Taffrail
H
0

Actually, I did not want to be dependent of anything else but Python (Cairo, Ink.., etc.) My requirements were to be as simple as possible, at most, a simple pip install "savior" would suffice, that's why any of those above didn't suit for me.

I came through this (going further than Stackoverflow on the research). https://www.tutorialexample.com/best-practice-to-python-convert-svg-to-png-with-svglib-python-tutorial/

Looks good, so far. So I share it in case anyone in the same situation.

Hydrastinine answered 27/7, 2020 at 10:18 Comment(2)
can you please include the relevant part of that article to your answer ?Osyth
looking at it, it seems to be identical to Sarang's answerOsyth
D
0

All the answer's here are great, but I figure I'll mention that I have made a simple library that loads SVG's files as pillow Image instances which can then be exported. It uses inkscape like in blj's answer, but renders to stdout so that no temporary files are made. There's some basic usage stuff in the README.

https://github.com/jlwoolf/pillow-svg

EDIT:
As suggested, here's a brief explanation, since the link could become invalid:

The library uses inkscape's command line interface to convert the image to a png of a specific size or dpi using the python subprocess library. By setting --export-filename to -, inkscape redirects the output to the stdout. The first two lines are discarded, and the remaining output is passed to PIL.Image.open, converting it to pillow image instance.

import subprocess
from PIL import Image

options = ["inkscape", "--export-filename=-", "--export-type=png", "file.svg"]

pipe = subprocess.Popen(options, stdout=subprocess.PIPE)

pipe.stdout.readline()
pipe.stdout.readline()

img = Image.open(pipe.stdout)

From there you can do whatever pillow image operations you need (like export as a jpg, resize, crop, etc).

EDIT 2:
Just added support for skia-python (haven't fully tested it, but seems to work so far). This way you can convert an svg to png with only a single pip install (no need to use inkscape).

Here is an explanation of how the library uses skia-python:

First, the svg file is loaded into a skia.SVGDOM. From there you can grab the SVGDOM's dimensions, using containerSize. Then a skia.Surface of the desired image output size is made. The canvas is scaled to fit the svg to the surface, and then the svg is rendered. From there, an image snapshot can be made, which can then be fed to PIL.Image.open.

import skia
from PIL import Image

skia_stream = skia.Stream.MakeFromFile("file.svg")
skia_svg = skia.SVGDOM.MakeFromStream(skia_stream)

svg_width, svg_height = skia_svg.containerSize()
surface_width, surface_height = 512, 512

surface = skia.Surface(surface_width, surface_height)
with surface as canvas:
    canvas.scale(surface_width / svg_width, surface_height / svg_height)
    skia_svg.render(canvas)

with io.BytesIO(surface.makeImageSnapshot().encodeToData()) as f:
            img = Image.open(f)
            img.load()

Edit 3:
I have fleshed out the library much much more. There is a command line utility now for easy svg conversion, along with more documentation explaining usage. Hope it helps!

Duelist answered 12/6, 2022 at 0:2 Comment(2)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Futuristic
While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - From ReviewReptant

© 2022 - 2024 — McMap. All rights reserved.