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?
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.
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
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}
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)
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
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.
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)
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.
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')
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)