在Python中将SVG转换为PNG

ram*_*am1 87 python svg rendering cairo

如何转换的svgpng,在Python?我正在存储svg一个实例StringIO.我应该使用pyCairo库吗?我该如何编写代码?

nem*_*ixx 65

这是我使用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')
Run Code Online (Sandbox Code Playgroud)

它就像一个魅力!

查看更多:cairosvg文件

  • 你好.你知道我怎么能这样做但没有写入文件?我需要从网络服务器将png内容推送到浏览器,这样用户就可以下载图像了.保存png文件不是我们项目中的有效选项,这就是我需要它的原因.谢谢 (5认同)
  • 我自己一直这样做.它基本上取决于处理Web请求时你手头的工具或框架,但无论它是什么,基本的想法是`svg2png`在`write_to`参数中接受`stream`对象,这可以要么是您的HTTP响应对象(在大多数框架中是一个类文件对象),要么是其他流,然后使用`Content-Disposition`标头将其提供给浏览器.见这里:http://stackoverflow.com/questions/1012437/uses-of-content-disposition-in-an-http-response-header (3认同)
  • 对于那些经历过该代码问题的人,就像我一样:1).`bytestring`接受字节,所以首先用`bytestring = bytes(svg,'UTF-8')`2转换字符串.文件模式应该是二进制的,所以`open('output.png','wb')` (3认同)
  • cairosvg仅支持Python 3.4+.他们已经放弃了Python 2的支持 (3认同)
  • 我没有“svg2png”,我不得不使用“cairosvg.surface.PNGSurface.convert(svg_str, write_to='output.png')”。 (2认同)

jsb*_*eno 57

答案是" pyrsvg " - librsvg的Python绑定.

有一个Ubuntu python-rsvg包提供它.搜索Google的名称很差,因为它的源代码似乎包含在"gnome-python-desktop"Gnome项目GIT存储库中.

我创建了一个极简主义的"hello world",它将SVG渲染到cairo表面并将其写入磁盘:

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")
Run Code Online (Sandbox Code Playgroud)

更新:截至2014年,Fedora Linux发行版所需的软件包是:gnome-python2-rsvg.上面的代码段列表仍然按原样运行.


blj*_*blj 39

安装Inkscape并将其命名为命令行:

${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -j -e ${dest_png}
Run Code Online (Sandbox Code Playgroud)

您也可以仅使用参数捕捉特定的矩形区域-j,例如坐标"0:125:451:217"

${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -j -a ${coordinates} -e ${dest_png}
Run Code Online (Sandbox Code Playgroud)

如果要在SVG文件中仅显示一个对象,可以使用-i在SVG中设置的对象ID 指定参数.它隐藏了其他一切.

${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -i ${object} -j -a ${coordinates} -e ${dest_png}
Run Code Online (Sandbox Code Playgroud)

  • +1因为这对于shell脚本来说也非常方便.有关Inkscape命令行的完整文档,请参阅http://inkscape.org/doc/inkscape-man.html. (2认同)
  • 这不是答案。这是一种解决方法。OP要求提供Python解决方案。 (2认同)

str*_*ics 27

我正在使用Wand-py(围绕ImageMagick的Wand包装器的实现)来导入一些非常先进的SVG,到目前为止已经看到了很好的结果!这是它需要的所有代码:

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

我今天刚刚发现了这一点,并且觉得值得分享其他任何可能因为大部分问题得到解答而已经过了一段时间的人.

注意:从技术上来说,我发现你甚至不必传递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)
Run Code Online (Sandbox Code Playgroud)

  • 如果你有一个svg` str`那么你首先需要像这样编码成二进制文件:`svg_blob = svg_str.encode('utf-8')`.现在,您可以使用上面的方法将`blob = svg_file.read()`替换为`blob = svg_blob`. (4认同)
  • 我得到错误`image.read(blob = svg_file.read(),format ="svg")NameError:名称'svg_file'未定义 (3认同)
  • 对于我的PNG,魔杖比开罗更好**. (2认同)
  • 在此示例中,假设svg_file是一个“文件”对象,设置svg_file会类似于:svg_file = File.open(file_name,“ r”)` (2认同)
  • 谢谢,`cairo`和`rsvg`'接受'方法对我的PDF不起作用.`pip install wand`和你的片段做了伎俩;) (2认同)

Sar*_*ang 17

我没有找到任何令人满意的答案。所有提到的库都有一些问题,比如开罗放弃对 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")
Run Code Online (Sandbox Code Playgroud)

我应该注意这些有什么限制吗?

  • 对于那些在 Windows 上工作的人来说,这是一个很好的解决方案,在 SO 级别绝对不需要依赖项。谢谢!! (3认同)

小智 12

试试这个:http://cairosvg.org/

该网站说:

CairoSVG是用纯python编写的,只依赖于Pycairo.众所周知,它适用于Python 2.6和2.7.

2016年11月25日更新:

2.0.0是一个新的主要版本,其更新日志包括:

  • 删除Python 2支持

  • @Ray,请在[CairoSVG跟踪器](https://github.com/Kozea/CairoSVG/issues)上发送错误报告/功能请求! (2认同)
  • @Ray,实际上-d/--dpi选项已经存在了一段时间了,而且我被告知在几周前在git版本中添加了对<clippath>的支持. (2认同)

小智 8

这是另一种不使用 rsvg 的解决方案(目前不适用于 Windows)。仅使用以下命令安装 cairosvgpip install CairoSVG

svg2png.py

from cairosvg import svg2png
svg_code = open("input.svg", 'rt').read()
svg2png(bytestring=svg_code,write_to='output.png')
Run Code Online (Sandbox Code Playgroud)

  • 另一种更简单的方法:`cairosvg.svg2png(url="/path/to/input.svg", write_to="/tmp/output.png")`。正如 Cairosvg 官方文档中所分享的:https://cairosvg.org/documentation/ (5认同)

Ada*_*erz 6

我在这里找到的另一个解决方案如何将缩放的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()
Run Code Online (Sandbox Code Playgroud)

PySide很容易从Windows中的二进制包安装(我将它用于其他事情,因此对我来说很容易).

但是,我注意到从维基媒体转换国家标志时出现了一些问题,所以也许不是最强大的svg解析器/渲染器.


Mar*_*oma 5

关于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)
Run Code Online (Sandbox Code Playgroud)