SVG is an awesome image format thats widely used, works in all browsers. SVG graphics make better apps and better games – and automatically “upgrade” themselves for future devices.
This post gives some simple 1-line / few lines of code recipes for using some of the main features of SVGKit – SVG implementation for iOS/OS X.
NOTE: this post refers to the 1.0.x version of SVGKit
Basic usage / installation
Install instructions are on the main GitHub page.
Basic usage / first-time usage info is on SVGKit 2013 – Usage.
Recipes
Load an SVG file like loading a PNG file
[objc]
SVGKImage* newImage = [SVGKImage imageNamed:@"imagename"];
[/objc]
Display an SVG file on-screen using an ImageView
[objc]
[self.view addSubView: [[SVGKFastImageView alloc] initWithImage:newImage];
[/objc]
…or an ImageView that supports CoreAnimation for every element
NB: the “Fast” imageview above saves everything as a single layer. Good for rendering, but bad for interaction. The “Layered” imageview here allows you to tap on any layer, rotate/animate/fade/drop-shadow/glow any element, etc.
[objc]
[self.view addSubView: [[SVGKLayeredImageView alloc] initWithImage:newImage];
[/objc]
Use a URL to load an SVG (open an SVG file *directly* from the web)
[objc]
// Splitting URL to multiple lines to make blogpost
// easier to read…
NSString* longURL = [NSString stringWithFormat:@"%@%@%@",
@"http://upload.wikimedia.org/",
@"wikipedia/commons/f/fd/",
@"Ghostscript_Tiger.svg";
NSURL* url = [NSURL urlWithString:longURL];
SVGKImage* newImage = [SVGKImage imageWithContentsOfURL:url];
[/objc]
Open an SVG from a custom source (maybe an in-memory SVG creation method)
First, create a class that conforms to SVGKSourceReader, i.e.:
[objc]
@interface MyNewClass : NSObject <SVGKSourceReader>
…
[/objc]
…then subclass SVGKSource, and over-ride the method:
[objc]
-(NSObject<SVGKSourceReader>*) newReader:(NSError**) error
[/objc]
Finally, use your customized SVGKSource to load your SVG:
[objc]
SVGKSource* myCustomSource = [[[MyCustomClass alloc] init] newReader:nil];
/** Other examples, using the default SVGKSource class:
SVGKSource* urlSource = [SVGKSource sourceFromURL: [NSURL …];
SVGKSource* fileSource = [SVGKSource sourceFromFilename: @"monkey.svg"];
*/
SVGKImage* newImage = [SVGKImage imageWithSource:myCustomSource];
[/objc]
Search an SVG file for particular tags / nodes / elements
SVG is an XML file, containing XML tags/nodes such as: “<svg>”, “<g>”, “<path>”, “<linearGradient>”, etc.
[objc]
NSString* tagToFind = @"linearGradient";
NodeList* result = [svgImage.DOMDocument getElementsByTagName:tagToFind];
for( Element* domElement in result )
{
// You can use the Element object directly:
domElement.tagName;
…
// …or, if it was parsed by the SVG parser, you can convert it to an SVGElement:
SVGElement* svgElement = (SVGElement*) domElement;
…
}
[/objc]
Search for sub-tags / sub-nodes of a particular tag/node
If you already have an SVGElement reference, you can search all its descendants:
[objc]
// To search the entire document, use:
// SVGElement* startPoint = newImage.DOMTree;
SVGElement* startPoint = … // from your code
NSString* tagToFind = @"linearGradient";
NodeList* result = [startPoint getElementsByTagName:tagToFind];
for( Element* domElement in result )
{
SVGElement* svgElement = (SVGElement*) domElement; // if your tags are all supported by SVGKit, they will be converted to SVGElement instances
…
}
[/objc]
Get a list of ALL descendant tags (from a particular node down)
[objc]
SVGElement* startPoint = … // e.g. for whole SVG doc, use: newImage.DOMDocument;
NodeList* allElements = [startPoint getElementsByTagName:@"*"];
[/objc]
Render one small part of the SVG file on its own
E.g. if you want to display a subset of the SVG, or want to export a single element:
[objc]
NSString* idInSVGFile = … // assuming your SVG file has an "id" attribute for this node
CALayer* absoluteLayer = [newImage newCopyPositionedAbsoluteLayerWithIdentifier:isInSVGFile];
…
// NB: "absoluteLayer" is now positioned in absolute space;
// if you add it to your window using e.g.:
[self.view.layer addSublayer: absoluteLayer];
// …it will appear in the same place as it appeared before,
// keeping all the offsets, rotations, etc
[/objc]
NOTE: there are several “newCopy…” methods, and each has different effects and outcomes. Read the method docs for each to decide which one you want to use. In a future version of SVGKit, we’d like to move these methods into a class of their own, and make it easier to see which one does what
Customise the parsing, using your own parser extensions
Create your custom class that adheres to SVGKParserExtension:
[objc]
@interface MyCustomSVGParserExtension : NSObject <SVGKParserExtension>
…
[/objc]
Then create a parser, INCLUDE THE DEFAULT extensions, and add your one on the end:
[objc]
MyCustomSVGParserExtension* myCustomExtension = [[MyCustomSVGParserExtension alloc] init];
SVGKParser* parser = [[SVGKParser alloc] init];
[parser addDefaultSVGParserExtensions]; // HIGHLY RECOMMENDED
[parser addParserExtension:myCustomExtension];
SVGKParseResult* result = [parser parseSynchronously];
SVGKImage* newImage = [[SVGKImage alloc] initWithParsedSVG:result];
[/objc]
Get help on why parsing failed (and warnings and line numbers!)
[objc]
SVGKImage* newImage = … // use methods above
// EITHER: parse using default parser:
SVGKParseResult* parseResult1 = newImage.parseErrorsAndWarnings; // this is a convenience pointer to (SVGKParser*).currentParseRun
// OR: use a custom parser:
SVGKParser* parser = … // use methods above
SVGKParseResult* parseResult2 = parser.currentParseRun;
[/objc]
And then you have the following info:
[objc]
/* array of NSError objects, each one a "WARNING" from the parser */
parseResult.warnings;
/* array of NSError objects, each one a "FATAL ERROR" from the parser – if your SVG didn’t render at all, this is why! */
parseResult.errorsFatal;
/* array of NSError objects, each one a "RECOVERABLE ERROR" from the parser – if your SVG didn’t render correctly, this is why! (although you probably still got to see something) */
parseResult.errorsRecoverable;
[/objc]
UPDATE: more Recipes!
For more recipes, see SVGKit Recipes part 2
(this covers answers to some of the common questions asked in the Comments below)