Wie konvertiere ich ein svg
in png
in Python? Ich speichere das svg
in einer Instanz von StringIO
. Soll ich die pyCairo-Bibliothek verwenden? Wie schreibe ich diesen Code?
Wie konvertiere ich ein svg
in png
in Python? Ich speichere das svg
in einer Instanz von StringIO
. Soll ich die pyCairo-Bibliothek verwenden? Wie schreibe ich diesen Code?
Antworten:
Die Antwort lautet " pyrsvg " - eine Python-Bindung für librsvg .
Es gibt ein Ubuntu python-rsvg-Paket, das es bereitstellt. Das Durchsuchen von Google nach seinem Namen ist schlecht, da der Quellcode im GIT-Repository des Gnome-Projekts "gnome-python-desktop" enthalten zu sein scheint.
Ich habe eine minimalistische "Hallo Welt" erstellt, die SVG auf eine Kairo-Oberfläche rendert und auf die Festplatte schreibt:
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 : Ab 2014 ist das erforderliche Paket für die Fedora Linux-Distribution : gnome-python2-rsvg
. Die obige Snippet-Liste funktioniert weiterhin wie sie ist.
cairo
die Höhe und Breite des Bildes selbst bestimmen zu lassen ? Ich habe in die *.svg
Datei geschaut , um die HÖHE und BREITE von dort zu extrahieren, aber beide sind auf eingestellt 100%
. Natürlich kann ich mir die Eigenschaften des Bildes ansehen, aber da dies nur ein Schritt in der Bildverarbeitung ist, ist dies nicht das, was ich will.
.get_dimension_data()
Methode, die für meine Beispieldatei (eine gut erzogene SVG) funktioniert - probieren Sie es aus.
Folgendes habe ich mit cairosvg gemacht :
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')
Und es funktioniert wie ein Zauber!
Weitere Informationen : cairosvg document
svg2png
ein stream
Objekt im write_to
Parameter aufzunehmen, und dies kann entweder Ihr HTTP-Antwortobjekt sein (welches in Die meisten Frameworks sind ein dateiähnliches Objekt oder ein anderer Stream, den Sie dann mithilfe des Content-Disposition
Headers an den Browser senden. siehe hier: stackoverflow.com/questions/1012437/…
bytestring
akzeptiert Bytes, also konvertiere den String zuerst mit bytestring=bytes(svg,'UTF-8')
2). open('output.png','wb')
svg2png
für mich, ich musste es benutzen cairosvg.surface.PNGSurface.convert(svg_str, write_to='output.png')
.
Installieren Sie Inkscape und rufen Sie es als Befehlszeile auf:
${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -j -e ${dest_png}
Sie können einen bestimmten rechteckigen Bereich auch nur mit Parametern fangen -j
, z. B. mit der Koordinate "0: 125: 451: 217".
${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -j -a ${coordinates} -e ${dest_png}
Wenn Sie nur ein Objekt in der SVG-Datei anzeigen möchten, können Sie den Parameter -i
mit der Objekt-ID angeben, die Sie in der SVG eingerichtet haben. Es verbirgt alles andere.
${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -i ${object} -j -a ${coordinates} -e ${dest_png}
Ich verwende Wand-py (eine Implementierung des Wand-Wrappers um ImageMagick), um einige ziemlich fortgeschrittene SVGs zu importieren, und habe bisher großartige Ergebnisse erzielt! Dies ist der gesamte Code, den es braucht:
with wand.image.Image( blob=svg_file.read(), format="svg" ) as image:
png_image = image.make_blob("png")
Ich habe das heute erst entdeckt und hatte das Gefühl, dass es sich lohnt, es für alle anderen zu teilen, die sich über diese Antwort hinwegsetzen könnten, da die meisten dieser Fragen schon eine Weile beantwortet wurden.
HINWEIS: Technisch gesehen habe ich beim Testen festgestellt, dass Sie nicht einmal den Formatparameter für ImageMagick übergeben müssen with wand.image.Image( blob=svg_file.read() ) as image:
war alles, was wirklich benötigt wurde.
BEARBEITEN: Nach einem Bearbeitungsversuch von qris finden Sie hier einen hilfreichen Code, mit dem Sie ImageMagick mit einer SVG-Datei mit transparentem Hintergrund verwenden können:
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
In diesem Beispiel wird angenommen, dass es sich um ein "Datei" -Objekt handelt. Die Einstellung svg_file
würde svg_file = File.open(file_name, "r")
cairo
und rsvg
"akzeptierte" Methode hat bei meinem PDF nicht funktioniert. pip install wand
und dein Snippet hat es geschafft;)
str
Sie zuerst wie folgt in eine Binärdatei codieren : svg_blob = svg_str.encode('utf-8')
. Jetzt können Sie die oben beschriebene Methode verwenden , durch das Ersetzen blob=svg_file.read()
mit blob=svg_blob
.
Versuchen Sie dies: http://cairosvg.org/
Die Seite sagt:
CairoSVG ist in reinem Python geschrieben und hängt nur von Pycairo ab. Es ist bekannt, dass es mit Python 2.6 und 2.7 funktioniert.
Update 25. November 2016 :
2.0.0 ist eine neue Hauptversion, deren Änderungsprotokoll Folgendes enthält:
- Löschen Sie die Python 2-Unterstützung
<clipPath><rect ... /></clipPath>
. Zweitens wird die Option -d (DPI) nicht verwendet.
Eine andere Lösung, die ich gerade hier gefunden habe Wie rendere ich eine skalierte SVG in ein 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 kann einfach von einem Binärpaket in Windows installiert werden (und ich verwende es für andere Dinge, daher ist es für mich einfach).
Beim Konvertieren von Länderflaggen aus Wikimedia sind mir jedoch einige Probleme aufgefallen, daher möglicherweise nicht der robusteste SVG-Parser / Renderer.
Eine kleine Erweiterung der Antwort von 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)
Ich fand keine der Antworten zufriedenstellend. Alle erwähnten Bibliotheken haben das eine oder andere Problem, wie Kairo, das die Unterstützung für Python 3.6 aufgibt (sie haben die Unterstützung von Python 2 vor etwa 3 Jahren eingestellt!). Auch die Installation der genannten Bibliotheken auf dem Mac war mühsam.
Schließlich fand ich die beste Lösung war svglib + reportlab . Beide wurden ohne Probleme mit pip installiert und der erste Aufruf zur Konvertierung von svg nach png funktionierte wunderbar! Sehr zufrieden mit der Lösung.
Nur 2 Befehle reichen aus:
from svglib.svglib import svg2rlg
from reportlab.graphics import renderPM
drawing = svg2rlg("my.svg")
renderPM.drawToFile(drawing, "my.png", fmt="PNG")
Gibt es irgendwelche Einschränkungen bei diesen, die ich beachten sollte?
Mit pycairo und librsvg ich die SVG-Skalierung und das Rendern einer Bitmap erreichen. Angenommen, Ihr SVG hat nicht genau 256 x 256 Pixel, die gewünschte Ausgabe, können Sie das SVG mit rsvg in einen Kairoer Kontext einlesen, es dann skalieren und in ein PNG schreiben.
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')
Von der Cario-Website mit einigen geringfügigen Änderungen. Auch ein gutes Beispiel für das Aufrufen einer C-Bibliothek aus 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
es bei mir nicht funktioniert hat. Ich musste es durch ein einfaches Abrufen von self.props.width
und ersetzen self.props.height
. Ich habe zuerst versucht, die RsvgDimensionData
Struktur wie auf der cairo-Website beschrieben zu definieren , aber ohne Erfolg.
Hier ist ein Ansatz, bei dem Inkscape von Python aufgerufen wird.
Beachten Sie, dass bestimmte Crufty-Ausgaben, die Inkscape während des normalen fehlerfreien Betriebs in die Konsole schreibt (insbesondere stderr und stdout), unterdrückt werden. Die Ausgabe wird in zwei Zeichenfolgenvariablen out
und erfasst 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 '?') )
Wenn Sie beispielsweise einen bestimmten Job auf meinem Mac OS-System out
ausführen, erhalten Sie Folgendes:
Background RRGGBBAA: ffffff00
Area 0:0:339:339 exported to 100 x 100 pixels (72.4584 dpi)
Bitmap saved as: /path/to/output.png
(Die Eingabe-SVG-Datei hatte eine Größe von 339 x 339 Pixel.)
Eigentlich wollte ich von nichts anderem als Python abhängig sein (Kairo, Tinte usw.). Meine Anforderungen sollten so einfach wie möglich sein, höchstens ein einfaches pip install "savior"
würde ausreichen, deshalb hat keiner der oben genannten nicht ' passt nicht zu mir.
Ich bin durchgekommen (weiter als Stackoverflow in der Forschung). https://www.tutorialexample.com/best-practice-to-python-convert-svg-to-png-with-svglib-python-tutorial/
Sieht soweit gut aus. Also teile ich es für den Fall, dass sich jemand in der gleichen Situation befindet.