Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting SVG with Embedded CSS to PDF in Python

I'm trying to generate a PDF image from an SVG image using Python. I've tried both CairoSVG and svglib. The problem is that in both cases the generated PDFs do not have any of the embedded CSS styles applied.

Here is a simple SVG file which should render a blue rectangle with a black border:

<?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>

When rendering a PDF of this SVG using CairoSVG, the PDF image is rendered as a black rectangle. Using svglib, there is no stroke or style applied to the rectangle so it is not visible. Is anyone aware of a way to convert an SVG with CSS styles to a PDF image in Python?

like image 507
jrothenbuhler Avatar asked Feb 15 '13 20:02

jrothenbuhler


2 Answers

(With help from @MonkeyWrench, since he didn't post an answer.)

According to the documentation,

CairoSVG can use lxml to parse the SVG file, and tinycss plus cssselect to apply CSS not included in the style attribute of the tags. If these packages are not available, CSS will only be supported in the style attributes.

To get started, I installed all the dependencies,

$ pip3 install cairosvg lxml tinycss cssselect

Then I created image.svg with the following contents:

<?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>

Finally, I executed cairosvg

$ cairosvg image.svg -o image.pdf

And sure enough, it was a blue rectangle.

blue

like image 121
James Lim Avatar answered Oct 22 '22 07:10

James Lim


Have you tried using the style attribute instead?

<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> 

It's ultimately the same as you have already, but maybe CairoSVG skips over style elements in your HTML.

like image 23
ncksllvn Avatar answered Oct 22 '22 07:10

ncksllvn