我需要从 Python 脚本将 SVG 转换为 PNG。有很多工具,我试过的(我在 Ubuntu 上):
inkscape
(Inkscape 命令行)rsvg-convert
来自librsvg2-bin
convert
(即 ImageMagick)
但是这些都不支持 CSS3 transform: matrix3d(...)
。到目前为止,我发现的唯一支持此功能的软件是 Firefox/Chrom[ium]/等,但它们似乎不允许命令行呈现为 PNG。
是否有任何特殊选项可以传递给上述选项之一,以获得完全支持 CSS3 的渲染? 还是还有其他我目前不知道的转换选项?
编辑 我现在尝试了更多工具,包括:
wkhtmltoimage
wkhtmltopdf 的一部分|- nodeshot (使用大量管道在本地服务器上提供 SVG,然后下载最终图像)
而且可能,虽然我无法测试,因为它只是 OS X
webkit2png
(感谢@Mark Setchell 的建议)
以上所有都不符合我的要求,因为它们是基于 WebKit 的并且 WebKit just doesn't support matrix3d in SVG尽管它确实适用于常规元素......
最佳答案
万岁,我找到了一个解决方案 - 但它有巨大的开销并且需要大量的东西:
基本思想是将您的 SVG 作为网站提供,然后使用 SlimerJS 渲染它。 , Firefox 的脚本化版本。与提到的其他方法不同,这使用 Gecko渲染 SVG,如上所述,Gecko ( unlike WebKit ) 在 SVG 中正确渲染 CSS3 3D 旋转。
您可能想使用 xvfb也是,所以你不必在渲染时看到 SlimerJS 窗口(它本身还不支持 headless )。
在本地服务器上提供 SVG/HTML
首先,您需要将 SVG 作为 HTML 页面中的图像提供。内联 SVG 或直接 SVG 对我不起作用。我推荐 http.server.BaseHTTPRequestHandler
,它同时提供 HTML 和纯 SVG(将在第二个请求中请求)。
html = """
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0;
}
</style>
</head>
<body>
<img src="http://localhost:8000/svg/%s" />
</body>
</html>
""" % svg_name
margin: 0;
删除任何网站周围的默认空间。
我使用 deamon=True
将服务器作为 Thread
启动,因此一旦我的脚本完成它就会关闭。
class SvgServer:
def __init__(self):
self.server = http.server.HTTPServer(('', PORT), SvgRequestHandler)
self.server_thread = threading.Thread(target=self.server.serve_forever, daemon=True).start()
SvgRequestHandler
应该是您的 BaseHTTPRequestHandler
(我假设有——或者将会有——一种直接从 SlimerJS 访问文件的方法,因为 Firefox 可以使用 file://
来做到这一点,但我无法让它工作。然后这个步骤将变得过时。)
用 SlimerJS 渲染
现在浏览器可以访问 SVG,我们可以调用 SlimerJS。 SlimerJS 只接受 JavaScript 文件作为输入,所以我们最好生成一些 JavaScript:
slimer_commands = """
var webpage = require('webpage').create();
webpage
.open('%s')
.then(function () {
webpage.viewportSize = { width: 1920, height: 1080 };
webpage.render('%s', { onlyViewport: true });
slimer.exit()
});
""" % (url_for_html_embedding_svg, output_file_name)
好处:使用 Promises 进行批处理,这比为我们要渲染的每个 SVG 启动单独的 SlimerJS 要快得多。我个人使用索引 SVG,根据需要进行更改。
slimer_command_head = "const { defer } = require('sdk/core/promise');" \
"var webpage = require('webpage').create();" \
"webpage.viewportSize = { width: 1920, height: 1080 };" \
"var deferred = defer();" \
"deferred.resolve();" \
"deferred.promise.then(function () {"
commands = [slimer_command_head]
for frame_index in range(frame_count):
command = "return webpage.open('%s'); }).then(function () { webpage.render('%s', { onlyViewport: true });" % (
'http://localhost:8000/html/%d' % frame_index,
FileManagement.png_file_path_for_frame(frame_index)
)
commands.append(command)
commands.append("slimer.exit(); });")
slimer_commands = ''.join(commands)
现在我们已经准备好脚本,将其保存到临时文件并执行:
with tempfile.NamedTemporaryFile(suffix='.js') as slimer_file:
slimer_file.write(bytes(slimer_commands, 'UTF-8'))
slimer_file.flush()
command = [
SLIMER_EXECUTABLE,
os.path.abspath(slimer_file.name)
]
if run_headless:
command.insert(0, 'xvfb-run')
os.system(' '.join(command))
run_headless
选项将 XVFB 命令添加到 headless 之前.
大功告成。
这很简单、快速且直接,不是吗?
如果您不能真正理解代码片段,请查看 the source code of the project I used it for .
关于python - 使用 CSS3 matrix3d 转换支持将 SVG 转换为 PNG,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31219906/