Comment convertir un svg
en png
, en Python? Je stocke le svg
dans une instance de StringIO
. Dois-je utiliser la bibliothèque pyCairo? Comment écrire ce code?
Comment convertir un svg
en png
, en Python? Je stocke le svg
dans une instance de StringIO
. Dois-je utiliser la bibliothèque pyCairo? Comment écrire ce code?
Réponses:
La réponse est " pyrsvg " - une liaison Python pour librsvg .
Il existe un package Ubuntu python-rsvg qui le fournit. La recherche de son nom sur 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 rend SVG sur une surface du Caire 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 paquet nécessaire pour la distribution Fedora Linux est: gnome-python2-rsvg
. La liste d'extraits ci-dessus fonctionne toujours telle quelle.
cairo
déterminer la HAUTEUR et la LARGEUR de l'image seule? J'ai regardé dans le *.svg
fichier pour en extraire la HAUTEUR et la LARGEUR, mais il est à la fois défini sur 100%
. Bien sûr, je peux examiner les propriétés de l'image, mais comme ce n'est qu'une étape dans le traitement de l'image, ce n'est pas ce que je veux.
.get_dimension_data()
méthode qui a fonctionné pour mon fichier d'exemple (un SVG bien comporté) - essayez-le.
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 cela fonctionne comme un charme!
Voir plus: document cairosvg
svg2png
prendre un stream
objet dans le write_to
paramètre, et cela peut être votre objet de réponse HTTP (qui dans la plupart des frameworks est un objet de type fichier) ou un autre flux, que vous diffusez ensuite au navigateur à l'aide de l'en- Content-Disposition
tête. voir ici: stackoverflow.com/questions/1012437/…
bytestring
accepte les octets, donc convertissez d'abord la chaîne avec bytestring=bytes(svg,'UTF-8')
2). le mode de fichier doit être binaire, doncopen('output.png','wb')
svg2png
pour moi, je devais utiliser cairosvg.surface.PNGSurface.convert(svg_str, write_to='output.png')
.
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 la coordonnée "0: 125: 451: 217"
${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -j -a ${coordinates} -e ${dest_png}
Si vous ne souhaitez afficher qu'un seul objet dans le fichier SVG, vous pouvez spécifier le paramètre -i
avec l'ID 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 du wrapper Wand autour d'ImageMagick) pour importer des SVG assez avancés et j'ai jusqu'à présent vu 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 de découvrir cela aujourd'hui, et j'ai eu l'impression que cela valait la peine d'être partagé pour quiconque pourrait se débattre avec cette réponse car cela faisait un moment que la plupart de ces questions n'avaient pas été répondues.
REMARQUE: techniquement, lors des tests, j'ai découvert que vous n'avez même pas besoin de passer le paramètre de format pour ImageMagick, donc with wand.image.Image( blob=svg_file.read() ) as image:
c'était tout ce qui était vraiment nécessaire.
EDIT: À partir d'une tentative d'édition par qris, voici un code utile qui vous permet d'utiliser ImageMagick avec un SVG qui a un fond 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)
image.read(blob=svg_file.read(), format="svg") NameError: name 'svg_file' is not defined
svg_file
est supposé être un objet "fichier" dans cet exemple, le paramètre svg_file
ressemblerait à svg_file = File.open(file_name, "r")
cairo
et rsvg
méthode « accepté » n'a pas fonctionné pour mon PDF. pip install wand
et votre extrait a fait l'affaire;)
str
, vous devez d'abord coder en binaire comme ceci: svg_blob = svg_str.encode('utf-8')
. Vous pouvez maintenant utiliser la méthode ci-dessus en remplaçant blob=svg_file.read()
par blob=svg_blob
.
Essayez ceci: http://cairosvg.org/
Le site dit:
CairoSVG est écrit en python pur et ne dépend que de Pycairo. Il est connu pour fonctionner sur Python 2.6 et 2.7.
Mise à jour du 25 novembre 2016 :
2.0.0 est une nouvelle version majeure, son changelog comprend:
- Supprimer le support de Python 2
<clipPath><rect ... /></clipPath>
. Deuxièmement, il ne prend pas l'option -d (DPI).
Une autre solution que je viens de trouver ici Comment rendre un SVG mis à l'échelle en 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 package binaire dans Windows (et je l'utilise pour d'autres choses, c'est donc facile pour moi).
Cependant, j'ai remarqué quelques problèmes lors de la conversion des drapeaux de pays de Wikimedia, donc peut-être pas l'analyseur / moteur de 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 __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)
Je n'ai trouvé aucune des réponses satisfaisantes. Toutes les bibliothèques mentionnées ont un problème ou un autre comme Cairo abandonnant le support de python 3.6 (ils ont abandonné le support de Python 2 il y a environ 3 ans!). De plus, l'installation des bibliothèques mentionnées sur le Mac était une douleur.
Enfin, j'ai trouvé que la meilleure solution était svglib + reportlab . Les deux installés sans accroc à l'aide de pip et le premier appel pour convertir de svg en png ont parfaitement fonctionné! Très content de la solution.
Seulement 2 commandes font l'affaire:
from svglib.svglib import svg2rlg
from reportlab.graphics import renderPM
drawing = svg2rlg("my.svg")
renderPM.drawToFile(drawing, "my.png", fmt="PNG")
Y a-t-il des limitations avec ceux-ci dont je devrais être conscient?
Utilisation de pycairo et librsvg j'ai pu réaliser une mise à l'échelle et un rendu SVG en bitmap. En supposant que votre SVG ne soit pas exactement 256x256 pixels, la sortie souhaitée, vous pouvez lire le SVG dans un contexte du Caire en utilisant rsvg, puis le mettre à l'échelle et écrire au format 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. Aussi un bon exemple de la façon d'appeler 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)
Handle.get_dimension_data
cela ne fonctionne pas pour moi. J'ai dû le remplacer par une simple récupération de self.props.width
et self.props.height
. J'ai d'abord essayé de définir la RsvgDimensionData
structure comme décrit sur le site Web du Caire, mais sans succès.
Voici une approche où Inkscape est appelé par Python.
Notez qu'il supprime certaines sorties cruelles qu'Inkscape écrit sur la console (en particulier, stderr et stdout) pendant un fonctionnement normal sans erreur. La sortie est capturée dans deux variables de chaîne, out
et 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 '?') )
Par exemple, lors de l'exécution d'une tâche particulière sur mon système Mac OS, j'ai out
fini par être:
Background RRGGBBAA: ffffff00
Area 0:0:339:339 exported to 100 x 100 pixels (72.4584 dpi)
Bitmap saved as: /path/to/output.png
(Le fichier svg d'entrée avait une taille de 339 par 339 pixels.)
En fait, je ne voulais pas dépendre d'autre chose que de Python (Cairo, Ink .., etc.) Mes exigences devaient être aussi simples que possible, au plus, un simple pip install "savior"
suffirait, c'est pourquoi aucun de ceux ci-dessus ne le faisait. t convient pour moi.
Je suis passé par là (en allant plus loin que Stackoverflow sur la recherche). https://www.tutorialexample.com/best-practice-to-python-convert-svg-to-png-with-svglib-python-tutorial/
Ça a l'air bien, jusqu'à présent. Alors je le partage au cas où quelqu'un se trouverait dans la même situation.