IJSVG is an Objective C library for drawing SVGs on macOS 14.6, iOS 16, tvOS 16, and visionOS 1 or later, without AppKit or UIKit dependencies. It uses Core Graphics for drawing and Core Image for SVG filters, with Metal and SIMD used to speed up supported effects.
- Region queries expose link targets and node bounds before drawing, with local, SVG user and destination coordinate spaces for measurements and overlays.
- CSS filters support color adjustments, blur and drop shadows, including ordered chains mixed with local SVG filter references and export as SVG primitives.
- Rendering quality modes now control image interpolation, filter coverage sampling and filter output interpolation, with faster options for thumbnails.
- Parsing, initial drawing and repeated filter rendering use fewer allocations and more cached work. Fixes cover nested pattern filter scaling, filter extents, SVG loading and a memory leak.
See the region and rendering quality examples below, and the supported CSS features and limitations under What it supports.
This release changes the node model for apps that inspect or construct SVG text:
IJSVGText.textContentnow containsIJSVGTextContententries instead of mixed strings and text nodes. Inspect each entry'skind, then readstringorspan. Construct entries withinitWithString:orinitWithSpan:; do not insert raw strings or nodes into the array.IJSVGAnchornow inherits fromIJSVGGroup. Anchors within text useIJSVGTextAnchor, which inherits fromIJSVGText. Both expose areference; code inspecting anchors must account for both classes.IJSVGNode.nodeTraitsexposes structural type flags inherited by subclasses. These are separate from the existing mutabletraitsflags for style behavior.
For example, replace a raw string in textContent with a typed entry:
textNode.textContent = @[
[[IJSVGTextContent alloc] initWithString:@"Hello"]
];The Core Graphics loading and drawing APIs and platform minimums remain the same as IJSVG 6. Apps using only those APIs do not need the text-node migration above.
IJSVG 6 adds iOS, iPadOS, tvOS, and visionOS support using a shared Core Graphics API. Native UI wrappers have been removed so the framework has no AppKit or UIKit dependency. This release includes breaking API changes.
Native UI integration has been removed: IJSVGView, IJSVGImageRep, the
NSImage category, NSPasteboardWriting, and loading from asset catalogs. Load
asset data in your app and pass it to init(data:) instead.
Raster APIs use CGImage throughout. Use init(cgImage:) and
renderCGImage(size:flipped:) instead of the convenience APIs for native images.
IJSVGImage.CGImage and filter primitive image retain their assigned pixels;
Objective C callers still release their own Create/Copy references.
Drawing requires an explicit CGContext. Offscreen scale defaults to 1 on
every platform; use renderingBackingScaleHelper to request a different scale.
The following changes were introduced in IJSVG 5 and still apply.
- Supported SVG element types have dedicated node classes, such as
IJSVGRect,IJSVGCircle,IJSVGPathandIJSVGGroup. Shared behavior lives in their base classes, and properties live on the classes that use them. Code that inspects, constructs or subclasses nodes should use the appropriate node class rather than assuming every property is available onIJSVGNode. - Colors are exposed as
CGColorRefin Objective C andCGColorin Swift, replacingNSColorin color properties, helpers and callbacks. This includes fills, strokes, current color, backgrounds, gradient stops and color replacement. Convert an AppKit color with.CGColorin Objective C or.cgColorin Swift. - XML parsing no longer loads DTDs or expands custom entities. Standard XML escapes and numeric character references remain supported.
- The default color space is now sRGB instead of device RGB. This applies to
colors, gradients and raster output.
Exported pixels can differ from earlier releases because the destination now
has a defined color profile.
IJSVGColor.defaultColorSpacereturns shared sRGB.
Color setters retain the supplied color. Gradient color arrays contain bridged
CGColor objects instead of NSColor objects. Code using Core Graphics creation
functions in Objective C must still release its own references after assigning
them. UI tint inputs and image wrappers belong in the consuming app.
Rendering and SVG export have received fixes across gradients, patterns, masks, clipping, text, markers and filters. The node tree remains editable and can still be exported to SVG.
Raster rendering also accepts an explicit RGB destination color space through
renderCGImage(size:flipped:colorSpace:) in Swift or
newCGImageRefWithSize:flipped:colorSpace:error: in Objective C. Pass sRGB for
bitmap exports or Display P3 when that destination is needed. The overload
preserves backing scale and flipping and reports unsupported color spaces or
bitmap creation failures through the existing error API.
SVG and CSS support is still incomplete, and some artwork may render differently from a browser. Please report rendering or export issues with a small example SVG. Performance improvements depend on the document and the effects it uses.
| Platform | Framework and Swift package | Example minimum | Example scheme |
|---|---|---|---|
| macOS | 14.6 | 14.6 | IJSVGExample |
| iOS and iPadOS | 16.0 | 17.0 | IJSVGiOSExample |
| tvOS | 16.0 | 17.0 | IJSVGtvOSExample |
| visionOS | 1.0 | 1.0 | IJSVGvisionOSExample |
The framework uses the same graphics APIs on every supported platform. Filter rendering requires a device that supports Metal. Individual accelerated paths also check the capabilities they need. watchOS is not supported.
Requires Xcode 16 / Swift 6 or later. The deployment minimums above apply to both the Swift package and the Xcode framework.
In Xcode, choose File > Add Package Dependencies, enter this repository's URL,
and add the IJSVG library product to your app target. For local development,
choose Add Local and select the repository root containing Package.swift.
Select version 6.1.0 or later for the features documented here. Review the breaking changes
and migration notes above when upgrading from an earlier version.
Import the library with import IJSVG in Swift or @import IJSVG; in Objective-C.
The package uses the existing Objective-C implementation and bundles its Metal
shader sources automatically. Package builds compile shaders on first use;
the existing Xcode framework continues to use its precompiled blur library.
Run swift build and swift test from the repository root to build and check
the XCTest and Swift Testing coverage for API behavior, rendering, and shader
resource loading. Shader compilation checks run when a Metal device is available.
The existing framework project and example applications remain available.
Select the IJSVGiOSExample scheme for iPhone or iPad, or IJSVGtvOSExample
with an Apple TV destination. Use IJSVGvisionOSExample with an Apple Vision Pro
destination. These schemes share one app target and display the bundled
car.svg. Select the matching simulator or device and run the scheme.
For manual integration, include the library sources and Metal shader resources, and import IJSVG.h into the files where you use SVGs.
The framework uses Foundation, Core Graphics, Core Text, ImageIO, Core Image, Metal, and Accelerate. It does not depend on AppKit or UIKit. The framework project supports macOS, iOS, tvOS, and visionOS, including device and Simulator destinations.
let svg = try IJSVG(parsing: svgText)
svg.renderingBackingScaleHelper = { 2 }
let pixels = try svg.renderCGImage(size: CGSize(width: 32, height: 32), flipped: true)
// pixels is a 64 × 64 CGImage. Wrap it for display in your app if needed.
let fromPixels = IJSVG(cgImage: pixels)Use flipped: true when displaying the resulting CGImage in SwiftUI, as the
examples do. When drawing into your own context, choose the orientation that
matches its coordinate system.
Use drawInRect:context: to draw into a supplied Core Graphics context. Your app
owns that context's coordinate system and display scale. ImageIO decodes raster
inputs and applies EXIF orientation. Embedded SVGs retain their vector document
and are rendered at the destination resolution. IJSVGImage.intrinsicSize is
measured in pixels for raster inputs; it no longer depends on the DPI of native images.
Support for iOS, tvOS, and visionOS requires IJSVG 6.0.0 or later.
Use the throwing initializers to receive parsing and file errors:
let svg = try IJSVG(contentsOf: fileURL)
let parsed = try IJSVG(parsing: svgText)
let decoded = try IJSVG(data: svgData)
let fromPath = try IJSVG(filePath: filePath)The convenience initializer IJSVG(svgString:) returns an optional when error
information is not needed. Metadata such as title and desc
and exporter delegates are optional and can be cleared with nil.
These annotations keep Objective C selectors unchanged. Swift callers of the previous error accepting initializers should use the names above. Optional properties now require normal optional handling instead of implicit unwrapping.
let cgImage = try svg.renderCGImage(size: CGSize(width: 64, height: 64), flipped: true)
let pdf = svg.pdfData()
let checkedPDF = try svg.renderPDF()Use pdfData(in:) or renderPDF(in:) to specify the PDF drawing rectangle.
The renderPDF methods throw when the underlying method reports an error,
even if it also returns data. These annotations do not add rendering validation
or change when the Objective C implementation reports errors.
The Objective C newCGImageRefWithSize:flipped:error: method imports as
renderCGImage(size:flipped:) in Swift. Convenience methods for native images are no
longer provided.
Core Graphics results use Swift memory management, including rendered images,
IJSVGUtils.flippedPath(_:), IJSVGCommand.makePath(commands:), and shared color
spaces. Do not call takeRetainedValue() or takeUnretainedValue() on these results.
Objective C callers still release newly created objects and do not release borrowed
node image, path, gradient, or shared color space references.
Parser base URLs can be nil. Missing node relationships, paint overrides, image
source data, filter inputs, and unsuccessful color lookups are optional in Swift.
Collections that are always initialized remain nonoptional.
After changing stroke styles or path geometry, fit overflowing artwork into the original viewBox without changing the output dimensions or aspect ratio:
CGRect bounds = [svg artworkBounds];
[svg fitArtworkToViewBox:YES];
// Remove the fitting scale when restoring the original artwork.
[svg fitArtworkToViewBox:NO];Swift callers use svg.artworkBounds() and
svg.fitArtworkToViewBox(enabled: true). Call fitting again after subsequent
style or geometry changes. Repeated calls replace the fitting transform rather
than accumulating scale. Fitting preserves the original canvas center.
Bounds include resolved fills, strokes, caps, joins, dashes, and transforms. They are conservative geometry bounds, not a pixel tight measurement of masks or clipping. Filter effects are excluded.
Query anchor regions before drawing to place link overlays in the same rectangle:
let drawingRect = CGRect(x: 0, y: 0, width: 240, height: 160)
let links = svg.regions(in: drawingRect)
for region in links {
// Place an overlay at region.rect; resolve region.value in your app.
print(region.rect, region.value ?? "")
}Each rendered anchor instance returns an IJSVGRegion in painting order. Its
value preserves the original href, including relative URLs and fragments.
Rectangles use SVG coordinates with Y increasing downward. Bounds include
transforms and viewport clipping, but are conservative for curved clips and
masks and exclude filters and occlusion by other artwork. The app owns hit
testing, URL resolution and navigation.
For general node measurements, use
regions(in:coordinateSpace:nodeTypes:),
regions(for:in:coordinateSpace:) or
regions(forIdentifier:in:coordinateSpace:) in Swift. For example, in Objective C:
NSArray<IJSVGRegion*>* regions = [svg regionsForIdentifier:@"badge"
inRect:drawingRect
coordinateSpace:IJSVGRegionCoordinateSpaceDestination];Choose local coordinates for geometry before the node transform (including child
transforms), user coordinates for geometry in the outer SVG, or destination
coordinates for geometry mapped into the drawing rectangle. Only destination
bounds are clipped to that rectangle. The drawing size resolves relative units
in every coordinate space. General node bounds include strokes and exclude
filters and masks; local bounds ignore ancestor clipping. A nil node type list
includes all rendered nodes, while an empty list includes none.
Regions expose the node type, source node, identifier, coordinate space and
instanceIndex, which distinguishes rendered instances sharing a node or ID.
Full resolution is the default. Set rendering options before drawing or exporting a raster image to choose a faster mode:
IJSVGRenderingOptions* options = [[IJSVGRenderingOptions alloc] init];
options.renderQuality = kIJSVGRenderQualityOptimized;
svg.renderingOptions = options;| Quality | Image interpolation | Filter coverage |
|---|---|---|
kIJSVGRenderQualityFullResolution |
High | Full sampling for nested filters |
kIJSVGRenderQualityOptimized |
Medium | Local sampling for thumbnails |
kIJSVGRenderQualityLow |
Low | No additional coverage samples |
The setting also controls filter output interpolation. Faster modes can change
edge pixels, so use full resolution where fidelity is more important than speed.
Document image-rendering hints can also affect image sampling.
IJSVG* svg = [[IJSVG alloc] initWithFilePathURL:someURLHere];
// or with and without extension to find it within the bundle
IJSVG* svg = [IJSVG SVGNamed:@"my_svg"];
CGImageRef svgImage = [svg newCGImageRefWithSize:CGSizeMake(100.f, 100.f) flipped:NO error:nil];
// Use or wrap the image, then release your reference.
CGImageRelease(svgImage);
Draw directly into a Core Graphics context supplied by your app:
[svg drawInRect:bounds context:context];
Use renderingBackingScaleHelper to supply the backing scale factor for custom drawing. Return the scale of the destination window or bitmap so rasterized effects, such as filters, use the intended resolution:
IJSVG * svg = ...;
svg.renderingBackingScaleHelper = ^{
return 2.0; // Example: a bitmap with two pixels per point
};
IJSVG exports its node and paint graphs back to SVG, including gradients, patterns, clipping, masks and filter definitions. Filters are serialized as SVG primitives so their effects remain editable in the exported document.
Marker instances are exported as positioned vector artwork, preserving their appearance.
To export an SVG:
IJSVG* svg ...
IJSVGExporter * exporter = [[IJSVGExporter alloc] initWithSVG:svg options:IJSVGExporterOptionAll];
NSString* svgString = exporter.SVGString;
This gives you an SVG string to save to a file. Export options include collapsing groups and converting transform matrices into individual transforms.
Text uses the same loading and drawing APIs as other SVG content:
NSString* source = @"<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 240 80'>"
"<text x='20' y='50' font-family='Helvetica' font-size='32' fill='#333'>"
"Hello <tspan fill='#087ea4'>SVG</tspan></text></svg>";
IJSVG* svg = [[IJSVG alloc] initWithSVGString:source];
CGImageRef image = [svg newCGImageRefWithSize:CGSizeMake(240, 80) flipped:NO error:nil];
// Use the rendered image.
CGImageRelease(image);IJSVG uses fonts installed on the system and falls back to another font if one
is missing, so text can look different on another device. Use textPath with an
href pointing to a path ID to place text along a curve. Use tspan to change
the style or position of part of the text.
- Elements: svg, defs, a, use, symbol, g, switch, path, clipPath, mask, image, circle, ellipse, rect, polyline, polygon, line, marker, text, tspan and textPath (including group hierarchy, inheritance and nested SVGs). Conditional processing includes
systemLanguageandrequiredExtensions. - Commands: A, M, L, H, V, C, S, T, Q and Z and full support for multiple parameters of each type.
- Transformations: matrix, rotate, translate, scale and skew transformations, plus CSS
transform-originandtransform-box. - Stroking: stroke color and opacity, dash arrays and offsets, line caps, miter/round/bevel joins, miter limits,
pathLengthcalibration andvector-effect="non-scaling-stroke". - Filling: fill color, fill mode (winding rules), fill opacity, linear gradients, radial gradients and patterns. Gradients support
color-interpolation="sRGB"and"linearRGB", including repeat/reflect spread modes;autouses sRGB. - Markers:
marker,marker-start,marker-midandmarker-endon paths, lines, polylines and polygons. Supports custom child artwork,markerUnits, reference points, marker dimensions,viewBox, clipping, fixed angles,autoandauto-start-reverseorientation, andcontext-fill/context-strokepaints. - Color: named SVG colors, HEX, RGB(A), HSL(A), OKLCH and
currentColor. - CSS cascade: embedded style sheets and inline styles, with specificity, source order and
!important. - CSS selectors: type, class, ID and universal selectors, descendant and child combinators, and adjacent and general sibling combinators. Attribute selectors support presence, equality, word, language prefix, prefix, suffix and substring matching, with
iandscase flags. Namespace selectors and top level@namespacedeclarations are supported. - CSS pseudo-classes:
:root,:scope,:empty,:lang(),:first-child,:last-child,:only-child, theirof-typevariants, and:nth-child(),:nth-last-child(),:nth-of-type()and:nth-last-of-type(). Child index selectors supportof <selector-list>. Logical selectors include:is(),:where(),:not()and:has()with relative selectors. - CSS values and geometry: custom properties with
var(),calc(),min(),max()andclamp()in supported length values, CSS geometry properties, and path data throughd: path("...")ord: none. - CSS media queries:
<style media="...">and@mediablocks, including nested blocks. Queries supportall,screenandprinttypes, comma separated alternatives,and, leadingnotandonly, viewport width and height, and portrait or landscape orientation. Width and height accept exact values,min-andmax-prefixes, and feature first comparisons such as(width >= 600px). - Context paints:
context-fillandcontext-strokein markers and<use>instances, including solid colors, gradients, patterns and nested uses. Context paint servers retain the referencing element's coordinate space. - Rendering hints:
shape-rendering(auto,optimizeSpeed,crispEdges,geometricPrecision) andimage-rendering(auto,optimizeSpeed,optimizeQuality), including inherited and CSS values. Shape speed/crispness hints disable antialiasing; image speed uses nearest-neighbor sampling and quality uses high-quality interpolation. - Painting and compositing:
paint-order, group opacity,mix-blend-mode,isolation, clipping, alpha/luminance masks,displayandvisibility. - Text: system font selection and fallback, font shorthand and OpenType settings, character positioning and rotation,
textLength/lengthAdjust, text on paths, baseline alignment, spacing, bidirectional and vertical text, decorations, whitespace handling and wrapping withinline-size. - Filters:
feBlend,feColorMatrix,feComponentTransfer,feComposite,feConvolveMatrix,feDisplacementMap,feMorphology,feTile,feFlood,feOffset,feImage,feMerge,feGaussianBlur,feDropShadow,feTurbulence,feDiffuseLightingandfeSpecularLighting. - CSS filter functions:
blur(),brightness(),contrast(),drop-shadow(),grayscale(),hue-rotate(),invert(),opacity(),saturate()andsepia(), including ordered chains mixed with localurl(...)filters. CSS functions use sRGB and export as SVG primitives. Numeric amounts support percentages and CSS math expressions. Blur and shadow lengths support absolute units,em,exand CSS math. Shadows default to the element color. Hue rotation supportsdeg,rad,grad,turnand calculated angles. - Filter inputs:
SourceGraphic,SourceAlpha,BackgroundImage,BackgroundAlpha,FillPaint,StrokePaintand named intermediate results.
The list above describes implemented features, not complete SVG or CSS conformance. IJSVG is a static artwork renderer; it does not provide a browser DOM, scripting, interactive document behavior or SVG/CSS animation playback.
- CSS support is limited to the selectors and at-rules listed above. Interactive pseudo-classes such as
:hoverand:focus, pseudo-elements, nested:has(), and the column combinator are not supported.@supports,@import,@font-face,@layerand CSS nesting are not implemented. - Media queries are evaluated during parsing against the document viewport using the
screenmedia type, including when the artwork is later exported to PDF. Drawing at a different size does not reevaluate the stylesheet. Supported media lengths includepx,in,pt,pc,cm,mm,emandrem, with a fixed 16px basis foremandrem. Other media features such as resolution, aspect ratio and user preferences, generalorexpressions, and reversed or chained range comparisons are not implemented. - Fragment references such as
href="#symbol"are supported, but external SVG document references such ashref="icons.svg#symbol"are not resolved. Ordinary<image>loading does not currently resolve relative paths against the source document URL. color-interpolationcontrols gradient stop interpolation. Per-element linear RGB compositing/blending is not implemented; general compositing still uses the drawing context's color space. Filter interpolation remains controlled separately bycolor-interpolation-filters.<foreignObject>content is skipped. HTML layout and embedded web fonts are not supported; text uses locally available fonts.
Useful areas for further compatibility work include the remaining CSS selectors and at-rules, resource URL resolution, and per-element compositing color spaces. Rendering and export edge cases still need testing even for features listed as supported.
Filters are evaluated as a graph, with support for filterUnits, primitiveUnits, filter and primitive regions, and sRGB or linear RGB color interpolation. Core Image provides the general evaluation path. Eligible operations use dedicated Metal kernels or SIMD CPU routines. The renderer selects the path automatically according to the filter graph, image size and available capabilities, and falls back when an accelerated path is unavailable or unsuitable.
Metal paths accelerate supported Gaussian blur and shadow configurations, as well as selected arithmetic composites. SIMD routines accelerate CPU blur, selected color matrices and local or backdrop compositing. Compatible blur and shadow jobs can be batched, and reusable buffers and cached blur weights reduce repeated work.
Shapes and paths continue to draw through Core Graphics. Filtered content is rasterized at the rendering scale and composited back into the drawing context.
IJSVG is loosely based on UIBezierPath-SVG by ap4y
SVG icons in example found around the net, some from Sketch App Resources all open source and free to use.