万岁,我找到了一个解决方案 - 但它的开销很大并且需要大量的东西:
基本思想是将您的 SVG 用作网站,然后使用 Firefox 的脚本版本 SlimerJS 呈现它。与提到的其他方法不同,它使用Gecko 来渲染 SVG,并且如上所述,Gecko (unlike WebKit) 在 SVG 中正确渲染 CSS3 3D 旋转。
您可能也想使用xvfb,因此您不必在渲染时看到 SlimerJS 窗口(它本身还不支持无头)。
在本地服务器上提供 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; 删除任何网站周围的默认空间。
我以Thread 和deamon=True 启动服务器,因此一旦我的脚本完成,它将关闭。
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。
你已经完成了。
这很简单、快速、直接,不是吗?
如果您无法真正遵循代码 sn-ps,请查看the source code of the project I used it for。