1

I am having some trouble using the following code to render some SVG into PNG data. The StringIO writer is used since the image is ultimately intended for use as the body of an HTTP response.

The result is a PNG of the correct dimensions, but it is completely transparent.

import rsvg
import cairo
import StringIO

def render_svg_to_png(svg_data):
    # Render
    svg = rsvg.Handle()
    svg.write(buffer=svg_data)

    img = cairo.ImageSurface(cairo.FORMAT_ARGB32,
                             svg.props.width,
                             svg.props.height)
    ctx = cairo.Context(img)
    svg.render_cairo(ctx)

    # Write to StringIO
    png_io = StringIO.StringIO()
    img.write_to_png(png_io)
    img.finish()

    return png_io.getvalue()

The SVG data being rendered is as follows:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:cc="http://creativecommons.org/ns#"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:svg="http://www.w3.org/2000/svg"
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    version="1.1"
    width="40"
    height="40"
    id="svg2">
    <defs
        id="defs4">
        <linearGradient
        id="linearGradient3769">
        <stop
            id="stop3771"
            style="stop-color:#ffffff;stop-opacity:1"
            offset="0" />
        <stop
            id="stop3773"
            style="stop-color:#000000;stop-opacity:1"
            offset="1" />
        </linearGradient>
        <radialGradient
        cx="13.895907"
        cy="15.277355"
        r="19.6875"
        fx="13.895907"
        fy="15.277355"
        id="radialGradient3775"
        xlink:href="#linearGradient3769"
        gradientUnits="userSpaceOnUse"
        gradientTransform="matrix(0.96746783,-0.96746783,0.95701248,0.95701249,-12.884457,12.690532)" />
    </defs>
    <metadata
        id="metadata7">
        <rdf:RDF>
        <cc:Work
            rdf:about="">
            <dc:format>image/svg+xml</dc:format>
            <dc:type
            rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
            <dc:title></dc:title>
        </cc:Work>
        </rdf:RDF>
    </metadata>
    <g
        transform="translate(0,-1012.3622)"
        id="layer1">
        <path
            d="m 39.375,19.776785 a 19.6875,19.6875 0 1 1 -39.375,0 19.6875,19.6875 0 1 1 39.375,0 z"
            transform="matrix(1.015873,0,0,1.015873,0,1012.2715)"
            id="path2991"
            style="fill:url(#radialGradient3775);fill-opacity:1;fill-rule:nonzero;stroke:none" />
    </g>
</svg>
dlp
  • 486
  • 1
  • 4
  • 14

1 Answers1

1

Works okay for me here:

import rsvg
import cairo
import StringIO

def render_svg_to_png(svg_data):
    # Render
    svg = rsvg.Handle(data=svg_data)
    img = cairo.ImageSurface(cairo.FORMAT_ARGB32, 
      svg.props.width, 
      svg.props.height)
    ctx = cairo.Context(img)
    svg.render_cairo(ctx)

    # Write to StringIO
    png_io = StringIO.StringIO()
    img.write_to_png(png_io)

    return png_io.getvalue()

svg_data = open('test.svg', 'r').read()
print render_svg_to_png(svg_data)

Ran it with output redirection to a .png file and confirmed it came up okay in an image viewing program.

cwgem
  • 2,739
  • 19
  • 15
  • The problem was actually to do with using ElementTree to modify the XML. The XML output from ET had its namespaces messed around with. This didn't bother Chrome, which I was using to test that code, but it seems to upset rsvg. I didn't notice this until I looked at the output from ET more closely. Switching to minidom fixed this problem. – dlp Mar 13 '13 at 14:20