web-dev-qa-db-fra.com

Convertir SVG en PNG en Python

Comment convertir un svg en png, en Python? Je stocke le svg dans une instance de StringIO. Devrais-je utiliser la bibliothèque pyCairo? Comment puis-je écrire ce code?

87
ram1

La réponse est " pyrsvg " - a Python obligatoire pour librsvg .

Il existe un Ubuntu paquet python-rsvg le fournissant. La recherche du nom de Google est médiocre, car son code source semble être contenu dans le référentiel GIT du projet Gnome "gnome-python-desktop".

J'ai créé un "hello world" minimaliste qui convertit le SVG en surface de cairo et l'écrit sur le disque:

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")

Mise à jour : à partir de 2014, le package nécessaire à la distribution Fedora Linux est: gnome-python2-rsvg. La liste d'extraits ci-dessus fonctionne toujours telle quelle.

55
jsbueno

Voici ce que j'ai fait en utilisant 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')

Et ça marche comme un charme!

Voir plus: document cairosvg

57
nemesisfixx

Installez Inkscape et appelez-le en ligne de commande:

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

Vous pouvez également capturer une zone rectangulaire spécifique uniquement à l'aide du paramètre -j, par exemple. coordonnée "0: 125: 451: 217"

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

Si vous souhaitez afficher un seul objet dans le fichier SVG, vous pouvez spécifier le paramètre -i avec l'identifiant d'objet que vous avez configuré dans le SVG. Il cache tout le reste.

${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -i ${object} -j -a ${coordinates} -e ${dest_png}
39
blj

J'utilise Wand-py (une implémentation de l'encapsuleur Wand autour d'ImageMagick) pour importer des SVG assez avancés et j'ai déjà obtenu d'excellents résultats! C'est tout le code qu'il faut:

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

Je viens tout juste de découvrir cela aujourd'hui et je pensais que cela valait la peine d'être partagé par quiconque pourrait s'opposer à cette réponse, car cela faisait longtemps que la plupart de ces questions n'avaient pas reçu de réponse.

REMARQUE: Techniquement, lors de tests, j'ai découvert que vous n'aviez même pas besoin de passer le paramètre de format pour ImageMagick, donc with wand.image.Image( blob=svg_file.read() ) as image: était tout ce qui était vraiment nécessaire.

EDIT: à partir d’une tentative d’édition par qris, voici un code utile vous permettant d’utiliser ImageMagick avec un fichier SVG doté d’un arrière-plan transparent:

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)
26
streetlogics

Essayez ceci: http://cairosvg.org/

Le site dit:

CairoSVG est écrit en pure python et ne dépend que de Pycairo. Il est connu pour fonctionner sur Python 2.6 et 2.7.

Mise à jour 25 novembre 2016 :

2.0.0 est une nouvelle version majeure, son changelog comprend:

  • Supprimer Python 2 support
11
user732592

Une autre solution que je viens de trouver ici Comment convertir un fichier SVG mis à l'échelle en une image 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 s'installe facilement à partir d'un paquet binaire sous Windows (et je l'utilise pour d'autres tâches, donc c'est facile pour moi).

Cependant, j'ai remarqué quelques problèmes lors de la conversion des drapeaux de pays depuis Wikimedia, donc peut-être pas l'analyseur/rendu svg le plus robuste.

6
Adam Kerz

Une petite extension sur la réponse de 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 __== '__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)
4
Martin Thoma

Mise à l'échelle SVG et rendu PNG

En utilisant pycairo et librsvg , j'ai pu obtenir une mise à l'échelle et un rendu SVG au format bitmap. En supposant que votre fichier SVG ne représente pas exactement 256 x 256 pixels, vous pouvez lire le fichier SVG dans un contexte Cairo à l'aide de rsvg, puis le redimensionner et l'écrire dans un fichier 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 contraignant

Sur le site Web de Cario avec quelques modifications mineures. Également un bon exemple d’appel d’une bibliothèque C à partir de 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)
1