在Python中将嵌入CSS的SVG转换为PDF

13 投票
3 回答
3152 浏览
提问于 2025-04-17 16:02

我正在尝试用Python把SVG图片转换成PDF格式的图片。我试过了两个工具,一个是CairoSVG,另一个是svglib。问题是,无论用哪个工具生成的PDF都没有应用任何嵌入的CSS样式。

这里有一个简单的SVG文件,应该能显示一个蓝色的矩形,外面有黑色的边框:

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="200" height="200" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <style type="text/css"><![CDATA[
      rect {
        fill: #1f77b4;
        stroke: black;
        stroke-width: 1;
        shape-rendering: crispEdges;
      }
    ]]></style>
  </defs>
  <rect x="50" y="50" width="100" height="100"></rect>
</svg>

但是用CairoSVG生成这个SVG的PDF时,结果只显示了一个黑色的矩形。而用svglib时,矩形没有任何边框或样式,所以根本看不见。有没有人知道怎么在Python中把带有CSS样式的SVG转换成PDF图片呢?

3 个回答

1

我建议你使用 PhantomJS

简单来说,它是一个无头的WebKit,主要通过JavaScript来驱动。

你可以看看 rasterize.js 这个脚本。

你可以获取某个区域的坐标,然后把这个部分导出(栅格化)成一张图片。接着,你可以使用任何PDF生成器,把这张图片嵌入进去。或者,你也可以用另一个脚本,通过PhantomJS直接生成PDF文件。

1

你有没有试过用style属性呢?

<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
  <rect x="50" y="20" width="100" height="100"
  style="fill:#1f77b4;stroke:black;stroke-width:1;shape-rendering: crispEdges;"
  stroke-opacity:0.9"/>
</svg> 

其实这和你现在用的方式是一样的,不过可能CairoSVG在处理你的HTML时跳过了style元素。

12

(感谢@MonkeyWrench的帮助,因为他没有发答案。)

根据文档

CairoSVG可以使用lxml来解析SVG文件,并且可以用tinycss和cssselect来应用不在标签样式属性中的CSS。如果这些包没有安装,CSS只会在样式属性中被支持。

为了开始,我安装了所有需要的依赖,

$ pip3 install cairosvg lxml tinycss cssselect

然后我创建了一个名为image.svg的文件,内容如下:

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="200" height="200" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <style type="text/css"><![CDATA[
      rect {
        fill: #1f77b4;
        stroke: black;
        stroke-width: 1;
        shape-rendering: crispEdges;
      }
    ]]></style>
  </defs>
  <rect x="50" y="50" width="100" height="100"></rect>
</svg>

最后,我执行了cairosvg

$ cairosvg image.svg -o image.pdf

果然,得到了一个蓝色的矩形。

blue

撰写回答