问题:在Python中将SVG转换为PNG
如何转换的svg
到png
,在Python?我将储存svg
在的实例中StringIO
。我应该使用pyCairo库吗?如何编写该代码?
回答 0
答案是“ pyrsvg ” -一个Python绑定的librsvg。
有一个提供它的Ubuntu python-rsvg软件包。在Google上搜索其名称很不方便,因为其源代码似乎包含在“ gnome-python-desktop” Gnome项目GIT存储库中。
我制作了一个极简的“ hello world”,它将SVG渲染到开罗表面并将其写入磁盘:
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")
更新:从2014年开始,Fedora Linux发行版所需的软件包是:gnome-python2-rsvg
。上面的摘录清单仍按原样工作。
回答 1
from cairosvg import svg2png
svg_code = """
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#000" stroke- 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')
它就像一个魅力!
查看更多:cairosvg文档
回答 2
安装Inkscape并将其作为命令行调用:
${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -j -e ${dest_png}
您也可以仅使用参数捕捉特定的矩形区域-j
,例如,坐标“ 0:125:451:217”
${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -j -a ${coordinates} -e ${dest_png}
如果您只想在SVG文件中显示一个对象,则可以使用-i
在SVG中已设置的对象ID 来指定参数。它隐藏了其他所有内容。
${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -i ${object} -j -a ${coordinates} -e ${dest_png}
回答 3
我正在使用Wand-py(围绕ImageMagick的Wand包装器的实现)导入一些非常高级的SVG,到目前为止,已经看到了不错的结果!这是所需要的全部代码:
with wand.image.Image( blob=svg_file.read(), format="svg" ) as image:
png_image = image.make_blob("png")
我今天才发现这个问题,觉得有必要与其他人分享这个问题,因为自从回答了大多数问题以来已经有一段时间了。
注意:从技术上讲,在测试中,我发现您甚至实际上不必传递ImageMagick的format参数,因此 with wand.image.Image( blob=svg_file.read() ) as image:
真正需要的是所有这些。
编辑:通过qris的尝试编辑,这是一些有用的代码,可让您将ImageMagick与具有透明背景的SVG结合使用:
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)
回答 4
试试这个:http : //cairosvg.org/
该网站说:
CairoSVG用纯python编写,仅取决于Pycairo。已知可以在Python 2.6和2.7上运行。
2016年11月25日更新:
2.0.0是一个新的主要版本,其更改日志包括:
- 放弃对Python 2的支持
回答 5
我在这里找到的另一个解决方案如何将缩放的SVG渲染到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可以从Windows中的二进制软件包轻松安装(我将其用于其他用途,因此对我来说很容易)。
但是,从Wikimedia转换国家标记时,我注意到了一些问题,因此可能不是最可靠的svg解析器/渲染器。
回答 6
关于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)
回答 7
我没有找到满意的答案。所有提到的库都存在某些问题,例如Cairo放弃了对python 3.6的支持(它们在3年前就放弃了Python 2的支持!)。另外,在Mac上安装上述库也是很痛苦的。
最后,我发现最好的解决方案是svglib + reportlab。两者都使用pip顺利安装并且首次调用将svg转换为png都工作得很好!非常满意的解决方案。
仅需2条命令即可完成操作:
from svglib.svglib import svg2rlg
from reportlab.graphics import renderPM
drawing = svg2rlg("my.svg")
renderPM.drawToFile(drawing, "my.png", fmt="PNG")
我应该注意这些限制吗?
回答 8
SVG缩放和PNG渲染
使用pycairo和librsvg,我能够实现SVG缩放并将其渲染为位图。假设您的SVG并非精确地为256×256像素(所需的输出),则可以使用rsvg将SVG读入Cairo上下文中,然后对其进行缩放并写入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绑定
从Cario网站进行一些小的修改。也是如何从Python调用C库的一个很好的例子
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)
回答 9
这是Python调用Inkscape的一种方法。
请注意,它可以抑制Inkscape在正常无错误操作期间写到控制台的特定输出(特别是stderr和stdout)。输出被捕获到两个字符串变量out
和中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 '?') )
例如,在我的Mac OS系统上运行特定作业时,out
最终导致:
Background RRGGBBAA: ffffff00
Area 0:0:339:339 exported to 100 x 100 pixels (72.4584 dpi)
Bitmap saved as: /path/to/output.png
(输入的svg文件的大小为339 x 339像素。)
回答 10
实际上,除了Python(Cairo,Ink ..等)之外,我不想依赖于其他任何东西。我的要求是尽可能地简单,最多只需要一个简单的pip install "savior"
就够了,这就是上述任何原因都不是的原因。不适合我。
我经历了这一点(在研究上比Stackoverflow还要深入)。 https://www.tutorialexample.com/best-practice-to-python-convert-svg-to-png-with-svglib-python-tutorial/
到目前为止看起来不错。因此,如果有人遇到相同的情况,我会分享。