views:

202

answers:

2

I'm writing an app that lets users generate images with Raphael.JS. One of the secondary features I want is to generate a PNG of the Raphael canvas.

Here's the general pipeline in my head:

  1. User inputs parameters
  2. We generate JS with Raphael calls
  3. We generate a JS wrapper that does the above and calls .innerHTML on the containing div, giving us SVG (which we then send somewhere)
  4. We execute the JS wrapper
  5. The SVG is sent to ImageMagick and out pops a PNG

Step 4 is the step I need some guidance on. The user could be using IE; we have no guarantee that the JS is ever executed in an SVG browser. In any case, we'd need this to run server-side for it to be reliable. So here are the three possibilities I've come up with so far:

  • Install Firefox on the server and run the result of (3) in Firefox. This option sucks because installing FF means installing a bunch of X stuff on our server, running FF carries a lot of overhead, and I don't really want to muck about with tracking the process and killing it once it's done.
  • Use Node.js + jsdom (http://github.com/tmpvar/jsdom). Downside here is that it's not clear how supported jsdom is - the purported site, jsdom.org, doesn't really exist. Also, I can't find any documentation.
  • Maybe do something with Rhino? As far as I can tell, Rhino has even more meager DOM support than Node.

So...all three of those options kind of suck. I think. Am I wrong about something? Is there another way?

A: 

You could try transforming the VML to SVG on the server before running it through ImageMagick. I know the project itself is PHP, but the conversion is done with XSL (the file is in the download archive) so ought to be portable to any server platform.

robertc
Cool...thanks. That might actually work - though my Spidey sense is tingling at the thought of relying on the user's browser's output. I can't put my finger on the risk, but relying on that running client-side kind of freaks me out. What do you think - am I just being paranoid? There's no way for a user to create a Raphael image without loading a page in which it is rendered, and I think we expect that our users have JS enabled...
rfrankel
@rfrankel You can, of course, never trust input from the browser and there's always going to be possible exploits (in the XSLT engine for instance) even with well formed input, but I should think validating that your input is in fact SVG would be a good start.
robertc
Sure - I wasn't even really thinking about the security risks (which I know how to deal with) so much as edge cases where we'll successfully create the Raphael image but not the PNG because the user's browser does something weird or crashes or whatever.
rfrankel
+1  A: 

Once you have your SVG document serialized on the client, all you need is an SVG renderer and/or rasterizer running on your server to produce the PNG. It's not clear to me what you think a JS wrapper will do, or why it is needed. As the SVG document you're sending will not contain dynamic content, all you should need is to send the serialized SVG document to a rasterizer on the server in order to rasterize it as PNG.

The SVG renderer/rasterizer could simply be a CGI script which calls ImageMagick, or could be something more sophisticated. Personally, I would recommend setting up a servlet running Apache Batik, which includes an SVG Rasterizer, and can be called programmatically. A quick google search indicates that this is a pretty common task for Batik: http://www.mail-archive.com/[email protected]/msg06116.html

echo-flow