I’m working on a game for the iPhone platform. The levels will be quite big, and on top of that I need them in 2 different resolutions (because of the iPhone 4 retina display). Having them in the bundle in a bitmap based format would make the final bundle several hundred megabytes big, which is unacceptable. So I figured that it would be better to store them in a vector based format instead, since I create the levels in InkScape anyway.
At first I was thinking about the PDF format. But then I realized that I could use the same vector data to construct the physics world in Box2D. And for this task, the SVG format is brilliant. It’s an easy-to-parse XML format and it can have arbitrary text-based data associated with each object. That means I can put implementation specific data in the file directly from InkScape (like if an object should be static or dynamic in Box2D for example).
As it turns out, though, CoreGraphics does not support the SVG format. Bummer. Sure, UIWebView can render SVG’s, but I could not find a good way to use that for off-screen rendering. So I went and started looking for an open source library that could render an SVG into a pixel buffer. I found only one; librsvg. And then a few others, but they all seemed to depend on librsvg.
There are two problems with librsvg:
1. It’s LGPL, which if I’ve understood correctly will require me to release my game under a compatible licence unless I link librsvg dynamically. Unfortunatly, this cannot be done in the iPhone SDK.
2. After hours of trying, I could not get librsvg to compile for the iPhone.
So I gave up on 3rd party libs and began writing my own SVG renderer in Obj-c. Turns out it wasn’t very hard to get the most basic stuff up and running.
And this is it. SVGQuartzRender. It’s by no means a complete implementation of the SVG specification, but it can render the most basic stuff found in an SVG, and it can conveniently render it to a CGImageRef.
This is how to use it, in a nutshell:
Somewhere in your class, the init method for example:
SVGQuartzRenderer *svgRenderer = [[SVGQuartzRenderer alloc] init]; // A delegate must be specified [svgRenderer setDelegate:self];
You also need to implement the <SVGQuartzRendererDelegate> protocol:
// This is called before rendering begins. Here you need to supply the CGContext where you want the
//rendering to be done. If you just want an empty, off-screen bitmap context, you can use the
//convenience method -(CGContextRef)createBitmapContext
- (CGContextRef)svgRenderer:(id)renderer
requestedCGContextWithSize:(CGSize)size
{
return [renderer createBitmapContext];;
}
// Will be called when rendering is complete
- (void)svgRenderer:(id)renderer
didFinnishRenderingFile:(NSString *)file
inCGContext:(CGContextRef)context
{
// Here's your CGImageRef!
CGImageRef svgDrawing = CGBitmapContextCreateImage(context);
}
In the XCode project, there is a simple Cocoa app that demostrates more thoroughly how it is used.
I’ve put up a GitHub repo for SVGQuartzRenderer. If you want it, you should get it from there.
Feel free to use this code how ever you like, commercially or non-commercially. Should you make any improvements I’d love to get a patch! :)