Convert SVG to PNG with Python on Windows
Asked Answered
K

3

11

Question: Which reproducible process can enable Windows Python users to render a SVG image into PNG?


Many questions/answers (such as Convert SVG to PNG in Python and Server-side SVG to PNG (or some other image format) in python, which are not duplicates for the reasons explained below) explain how to convert a SVG to PNG with Python.

Unfortunately, none of them are ready-to-use for Python + Windows. After more than 20 minutes, and many different attempts, I'm still unable to do it. More details about failing attempts:

  • Installing cairo on Windows is not straightforward, we have to use Gohlke's binaries Intalling pycairo with Python 3.7 on Windows :

    pip install pycairo-1.20.0-cp37-cp37m-win_amd64.whl
    
  • Even once cairo is installed, rsvg (from main answers of Server-side SVG to PNG (or some other image format) in python, Convert SVG to PNG in Python) is not available for Windows:

    pip install rsvg   # or pyrsvg
    > ERROR: No matching distribution found for pyrsvg
    
  • Solutions with svglib or reportlab don't work out-of-the-box on Python3 + Windows:

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

    Indeed:

    AttributeError: 'Image' object has no attribute 'fromstring'
    

So a solution - specific for Windows - would be helpful.

Kuntz answered 17/1, 2021 at 11:6 Comment(9)
You cannot encode vector graphics data in a format that is raster based without loss of information. You're going to have to answer this question first: How much information are you willing to sacrifice?Subtangent
@Subtangent I'm looking for a PNG export, for a given image size, e.g. width=1000px (Of course a SVG can be infinitely zoomed without loss of quality, which will not be the case for a PNG, but I'm ok with this).Kuntz
That svglib example worked for me on Windows, I couldn't reproduce your error. Is the problem specific to certain SVG files you have?Teacart
@LukeWoodward Which versions of Python, svglib, reportlab do you have? I'll try to pip install the same versions.Kuntz
I have Python 3.7.3 installed, and the latest svglib and reportlab (1.0.1 and 3.5.59), which I recently installed from pip without specifying a version number for either. Also, could you please edit your question to include the full traceback of that AttributeError you were receiving?Teacart
I reinstalled with the same versions than you, and it works indeed. I think you can post this as an answer!Kuntz
Did you reinstall Python as well, or just svglib and reportlab?Teacart
Just the two last ones @LukeWoodward.Kuntz
You should include updated answers to either or both of the questions you linked, now that you have a solution.Selfrespect
T
10

From the comments, the solution was to install svglib version 1.0.1 and reportlab 3.5.59.

Teacart answered 17/1, 2021 at 12:41 Comment(5)
This answer is life saver. I had reportlab 3.5.49 and still i was getting Attributerror. But with the required update its working fine.Xe
Thanks a lot, you really saved my life. Great job!Huggins
I tried using reportlab 4.0.8 + svglib 1.5.1 on python 3.11.4 on windows, and I get the following : ModuleNotFoundError: No module named 'rlPyCairo'Duckett
@DanteMarshal: at the time I wrote this answer, reportlab 4 hadn't been released. However, having just tried, I can reproduce your error with the same versions of reportlab and svglib you are using. The fix is merely to install rlPyCairo.Teacart
If you have issues with transparency/opacity with this solution either look at #68023125 or at the alternative solution with CairoSVGHysterectomy
M
1

I couldn't get cairosvg to work in Windows, but found pygame mostly works without the hassle of gathering libraries.

import pygame

surface = pygame.image.load("shrubbery.svg")
pygame.image.save(surface, "shrubbery.png")

WebP, AVIF, and JPEG XL are replacing PNG.

Miser answered 14/4 at 10:43 Comment(0)
H
0

After comparing several solutions and finding out how to get libcairo working on a Windows computer (which can be a bit tricky) I recommend the following rather simple solution:

  1. Install CairoSVG, i.e. pip install CairoSVG
  2. If libcairo-2.dll is not on the Windows path of your computer (i.e. where libcairo-2.dll fails) and you do not know where to find it, install the GTK+ Runtime (<8 MB download, 14 MB when installed) with checkbox Set up PATH environment variable to include GTK+ checked (or provide the DLL folder path below yourself)

Now it can still happen that import cairosvg fails because there might be incompatible dependencies like zlib1.dll on your Windows path. To avoid such complications use the following Python script for conversion, which makes sure that libcairo-2.dll and its dependencies are loaded from the same folder. Provide the path to the SVG file as command line argument or in the global variable PATH_TO_SVG:

import os
import subprocess
import sys

# locate cairo dll
def _findLibCairoInstallFolder():
    CAIRO_DLL = 'libcairo-2.dll'
    consoleOutput = subprocess.check_output('where ' + CAIRO_DLL)
    assert CAIRO_DLL.encode() in consoleOutput,\
        f"{CAIRO_DLL} not on Windows path. Do you know its install folder? Have you the GTK+ Runtime for Windows installed?"
    cairoDllFirstLocation = consoleOutput.split(b'\r\n')[0].decode()
    cairoDllInstallPath = cairoDllFirstLocation.split(CAIRO_DLL)[0]
    return cairoDllInstallPath

# find or provide path to installation folder of cairo dll
g_cairoDllInstallPath = _findLibCairoInstallFolder()
#g_cairoDllInstallPath = r"C:\Program Files (x86)\GTK2-Runtime\bin"

# locally fix windows environment variable PATH so that libcairo-2.dll can be loaded
def _fixWindowsPathForLib(dllInstallPath):
    # make sure dependencies are loaded from the same folder
    os.environ['PATH'] = os.pathsep.join((dllInstallPath, os.environ['PATH']))

_fixWindowsPathForLib(g_cairoDllInstallPath)
import cairosvg

PATH_TO_SVG = 'example.svg'

def svg2png(inputPath, outputPath):
    with open(inputPath) as fileIn:
        svgCode = fileIn.read()
        cairosvg.svg2png(bytestring=svgCode, write_to=outputPath)


if __name__ == '__main__':
    if len(sys.argv) > 1:
        g_inputPath = sys.argv[1]
    else:
        g_inputPath = PATH_TO_SVG
    if len(sys.argv) > 2:
        g_outputPath = sys.argv[2]
    else:
        g_outputPath = g_inputPath + '.png'

    svg2png(g_inputPath, g_outputPath)
Hysterectomy answered 25/12, 2023 at 6:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.