I’ve spent a bit of time playing around with HTML5’s
canvas element lately. It’s a fun new toy and has a lot of potential to be useful. But the biggest headache I’m finding so far is the lack of authoring tools.
SVG has been around for ages, whereas Canvas is still relatively new. (Mozilla’s Vladimir Vukićević has a good overview presentation of the differences between the two, and when and where to use each.) SVG support is built into plenty of graphic editing tools; Canvas support is so far sadly lacking, although Matt May pointed me to this YouTube video that shows off the upcoming Canvas support Adobe’s CS5 suite will have, whenever it becomes available.
In the meantime, most of the Canvas demos we’ve seen thus far have mostly featured simple primitive shapes like lines and ellipses for good reason: it’s too hard to build up a reasonably complex vector image by manually plotting bezier curves.
Over the past few days I’ve tried out various ways to get around this problem. I came up with two methods of taking vector shapes out of Illustrator and rendering them with Canvas, both involving an intermediate step as SVG first.
So to start, from Illustrator (or any other vector editing application capable of doing so) export your artwork to SVG. You’ll find the SVG option in the Save As / Save a Copy dialog, and I’ve found the SVG profile you choose doesn’t really make much of a difference (though for the sake of argument I’ve been using 1.1).
We’ll use this happy little cloud image as our reference file:
This method is only theoretical so if you’re looking for the actual how-to, skip ahead to #2. I figure it might be worth writing this up anyway because, even though I couldn’t get it working, perhaps it’ll provide enough of a starting point for someone else to pick up where I left off and build a proper converter.
SVG and Canvas are both essentially vector drawing tools; Canvas is more pixel-oriented, but you are certainly able to plot lines and curves mathematically. Canvas is also limited to fewer primitive shapes, but there are obvious parallels between the two.
I spent a bit of time looking into the bezier commands in particular. In SVG, to plot a bezier curve, you do something like this:
<path d="C x1,y1 x2,y2 x,y" />
In Canvas, it’s this instead:
ctx.bezierCurveTo(x1,y1, x2,y2, x,y);
Different syntax, but the same basic components: you’re drawing a line from the current pen position to the x, y value, and before that you have two additional points (x1, y1 and x2, y2) that set your handles. (More SVG path commands, Canvas path methods.) It’s worth noting that SVG is more forgiving about commas; each coordinate must be separated by a comma for the Canvas method, but they’re strictly optional in the SVG example. This is relevant because Illustrator’s SVG export seems to be wildly inconsistent about when and how many commas each command uses.
Given the similarities, I thought it might be fairly straightforward to manually tweak the SVG output into Canvas drawing functions.
bezierCurveTo, and so forth.
<path d=" M 62.58, 31.96 c -0.711,0 -1.811,0.062 -3.181,0.165 c -0.566 -6.309 -5.862 -11.255 -12.318 -11.255 c -2.363,0 -4.564,0.675 -6.442,1.824 "/>
ctx.moveTo(62.58, 31.96); ctx.bezierCurveTo(-0.711,0,-1.811,0.062,-3.181,0.165); ctx.bezierCurveTo(-0.566,-6.309,-5.862,-11.255,-12.318,-11.255); ctx.bezierCurveTo(-2.363,0,-4.564,0.675,-6.442,1.824);
This did not work. I suspect the absolute vs. relative coordinate difference between SVG’s
C commands tripped me up, but after a half hour or so of poking around this was all I had to show for it:
Still, even if I’d have managed to get it right, I’d rather not have to manually massage my SVG output every time I want a new Canvas drawing. Which leads me to method #2.
One of the main reasons I bothered to attempt a manual conversion in the first place was because after an extensive search it appeared that people are mostly interested in converting Canvas to SVG. There are very few articles and tools that cover going the other way, which is what we’re after. Maybe I didn’t come up with exactly the right search term, but I was finding so little I almost gave up entirely.
Then after one last shot in the dark, I managed to stumble across SVGToCanvas, a Java library that promised to do exactly what it sounds like, with a few disclaimers and a major caveat:
- You need Java 6. Otherwise known as 1.6, this comes installed with Mac OS X Snow Leopard but previous versions will need to upgrade. I believe this is the download necessary for Leopard, if you’re on an even older version you’re on your own. No idea what the Windows situation is, but this might be a good place to start.
- You need to run it on the command line. I know this will freak out some designers, but really, it’s not terribly difficult.
- You mainly get outlines for now. This would be the big ugly caveat. Sometimes you get colour and gradients, sometimes you get mixed-up colour and gradients, mostly you don’t. Plan to re-add them manually. Hopefully this will work better in a future version of the library, but still, having outlines is a solid start.
Still with me? Great, go grab the JAR file and drop it on your hard drive somewhere easy to find. For now, probably best to drop it in the same folder with the SVG files you’re going to convert.
Now, load up the terminal, and find your way to the same directory. Here’s a quick command line primer that ought to get you going. The
pwd commands in particular are the ones you need.
(If you need a bit more help than that: put the SVG and JAR files in a folder on your Desktop called ‘canvas’. When you open up the terminal, type this minus quotes: ‘cd ~/Desktop/canvas’. Hit return. You’re good, keep reading.)
Run the converter with the following command:
java -jar svg2canvas.jar -o cloud.html cloud.svg
From left to right: we’re invoking Java with the SVGToCanvas library, then by -o cloud.html we’re specifying the output will be written to cloud.html, otherwise it just displays the output in the terminal (which can be handy if you’d like to just copy and paste without managing temporary files). Then finally at the end, cloud.svg is the input SVG file that we had previously generated from Illustrator.
That generates an HTML file which contains a
In this case it worked, though it added a stroke. When it’s just the outline, you can restore the colour by manually tweaking the code. Add a
fillStyle method before the draw, and a
ctx.fillStyle(#4a6481); ... (drawing commands here) .. ctx.fill();
Not too difficult for simple shapes. I’d hate to have to manually re-add the subtle gradients for more complicated illustrations, but it’s nice to know the outline conversion is fairly robust:
One more thing: I’d recommend flattening the vector art as much as possible. Join shapes that can be joined, expand effects and compound paths and masks, and generally clean up the artwork to as few points as possible. Smaller file sizes, more chance of success upon conversion.
So there you go. It’s still a fairly painful way to get your vector work into a
canvas, but until we get some better tools or built-in support for our existing tools, it’s one way to fill the gap.