python - 使用 CSS3 matrix3d 转换支持将 SVG 转换为 PNG

标签 python css svg png image-conversion

我需要从 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/

相关文章:

html - 高度 : 100% to use the remaining height?

javascript - 动画不适用于所有 anchor 标记

Python 在多线程中 fork

javascript - JQuery Mobile Panel Widget – 打开可折叠列表会导致在扩展到页面高度之外时跳转滚动到页面 div 的底部。为什么?

python - 为什么我不能 pickle typing.NamedTuple 而我可以 pickle collections.namedtuple?

html - 某些 CSS3 动画在 eBay 中不起作用说明

javascript - 在 Raphaël 的路径上附加文字?

qt - 带有 SVG 的 QIcon 显示为黑色

python - 在CNN代码中添加图像增强功能以​​提高准确性

python - 我的计数器运行不正常