From SVG to Canvas and Back

SVG Open 2010

Samuli Kaipiainen

University of Helsinki
Department of Computer Science

Matti Paksula

University of Helsinki
Department of Computer Science

Discussion

From: Jeff Schiller 
Date: Sun, 11 Oct 2009 16:45:48 -0500
Message-ID: 
To: David Storey 
Cc: SVG IG List 

Great list!

I had a couple stray ones also:

* adopt html5 offline manifest attribute on top-level svg element
* toDataUrl() on SVGDocument (mentioned at conf)

Another

From: Jon Ferraiolo 
Date: Sat, 3 Oct 2009 18:17:51 -0700
To: www-svg@w3.org
Message-ID: 

At SVG Open, there was discussion today about adding Canvas's pixel grabbing APIs to SVG, with claims that SVG implementations don't necessarily retain a rendering surface. It now occurs to me that there is a CSS property ('enable-background') in the SVG 1.1 spec just for this purpose:
From: Robert O'Callahan 
Date: Mon, 5 Oct 2009 09:55:42 +1300
Message-ID: <11e306600910041355j2e448ad5oeacd68d607789dbd@mail.gmail.com>
To: Jon Ferraiolo 
Cc: www-svg@w3.org

On Mon, Oct 5, 2009 at 2:21 AM, Jon Ferraiolo  wrote:

> Sounds intriguing to me. Maybe:
>
> ...
>

Sorry, that wasn't what I meant. What I meant was
var canvas = document.createElement("canvas");
canvas.drawImage(svgElement);
var data = canvas.getImageData(...);

Mozilla documentation

"Mozilla's canvas is extended with the drawWindow() method"
.. "It is not allowed in normal HTML pages)"

"With this method, it is possible to fill a hidden IFRAME with arbitrary content (e.g., CSS-styled HTML text, or SVG) and draw it into a canvas"

So let's do this right now!

Motivation

SVG is great (for vectors), but we want it out of the sandbox!

Canvas to SVG

// Get base64-encoded PNG from Canvas
var png_dataurl = canvas.toDataURL();

// Include into SVG image element
svg_img.setAttributeNS(
         "http://www.w3.org/1999/xlink",
         "xlink:href",
         png_dataurl);

SVG to Canvas

SVG to Canvas client-side

// Serialize the SVG DOM as XML
svg_xml = (new XMLSerializer())
  .serializeToString(svg);

// Base64-encode the XML as data URL
img.src = "data:image/svg+xml;base64,"
  + btoa(svg_xml);

// Draw the SVG-in-img into Canvas
canvas.ctx.drawImage(img);

Works in all browsers that

Security issues

  -------  Comment #3 From  Oliver Hunt   2009-09-16 21:35:26 PST  -------

(In reply to comment #2)
> (In reply to comment #1)
> > We should make sure to test svg data urls to make sure they don't get through.
> 
> You mean something like data:text/svg,...
> ?
> 
> Why shouldn't that get through?

The specific issue i think is that you can do

data:application/xml+svg,<svg><image src="evil.com"/></svg> or whatever.  However i *think* we would catch that as being a multi-origin source.  I think Sam's point was that we need to have a test that ensures the correct restrictions are in place.



Let's see how that looks like!

Too much security?

Proposal: SVG.toDataURL()

Motivated by missing functionality and security issues:

SVG.toDataURL( [type],
               [keepNonSafe=false],
               [keepOutsideViewport=false] )
type
Default: image/svg+xml.
Must support: image/png.
keepNonSafe
Export non-safe (image etc) elements.
keepOutsideViewport
Export all drawn content, even if not visible.

SVG.toDataURL.js library

We can implement SVG.toDataURL with JavaScript (while waiting for native support…)

SVG.toDataURL.js provides:

// Adds .toDataURL() to SVG prototype
SVGElement.prototype.toDataURL = function(type) { ... }

// Easy SVG to PNG export
var pngDataURL = mySVGelement.toDataURL("image/png");
imgElement.setAttribute("src", pngDataURL);

http://github.com/sampula/SVG.toDataURL

Compatibility

Works with current major browsers: Safari (4.1), Chrome (5.0), Firefox (3.6), Opera (10.60), IE9.

PARIS FINALE

Greetings to / salutations à… Jeff/codedread Doug/SVG-Whiz Andreas/carto.net Brad/Google Klaus/foreignObject Bianca/JSXGraph Rob/Google Andreas/bytestorm.eu Hillel/shtetl.koshergate.org Internet Explorer/Good job with IE9 ♥