Skip to content
IconJarPublic

About

MacOS SVG rendering and exporting library

Topics

Resources

Stars

176 stars

Watchers

13 watching

Forks

Latest commit

 

History

783 Commits

Folders and files

Repository files navigation

IJSVG 5.0

IJSVG is a Cocoa library for drawing SVGs in macOS 14.6 and later. It uses Core Graphics for drawing and Core Image for SVG filters, with Metal and SIMD used to speed up supported effects.

You can also copy an IJSVG object to the pasteboard. It provides PDF data so apps such as Sketch and Photoshop can paste the artwork as vectors.

What is new in IJSVG 5?

IJSVG 5 improves parsing, first draw performance and memory use, with a clearer node structure and Core Graphics colors throughout the graphics pipeline. This release includes breaking API changes.

Breaking changes

  • Supported SVG element types have dedicated node classes, such as IJSVGRect, IJSVGCircle, IJSVGPath and IJSVGGroup. 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 on IJSVGNode.
  • Colors are exposed as CGColorRef in Objective C and CGColor in Swift, replacing NSColor in color properties, helpers and callbacks. This includes fills, strokes, current color, backgrounds, gradient stops and color replacement. Convert an AppKit color with .CGColor in Objective C or .cgColor in 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, including the NSImage convenience methods. Exported pixels can differ from earlier releases because the destination now has a defined color profile. IJSVGColor.defaultColorSpace returns 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. The Interface Builder tint input continues to accept NSColor.

Rendering and export

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.

Quick Start

The framework and example application target macOS 14.6 or later. Filter rendering requires a Metal-capable device. Individual accelerated paths also check the device capabilities they need.

Swift Package Manager

Requires Xcode 16 / Swift 6 or later and macOS 14.6 or later.

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 5.0.0 or later for the current API. Review the breaking changes above when upgrading from an earlier major 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 Objective-C XCTest 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 application remain available. For manual integration, include the library sources and Metal shader resources, and import IJSVG.h into the files where you use SVGs.

Swift loading and optional values

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, view SVG content, 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.

Swift rendering and Core Graphics ownership

let image = try svg.renderImage(size: CGSize(width: 64, height: 64))
let flipped = try svg.renderImage(size: CGSize(width: 64, height: 64), flipped: true)
let fitted = try svg.renderImage(fitting: CGSize(width: 64, height: 64), flipped: false)
let cgImage = try svg.renderCGImage(size: CGSize(width: 64, height: 64), flipped: false)
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 selectors are unchanged. Swift calls to the image methods with an error parameter now use renderImage, and newCGImageRef uses renderCGImage. The existing image(with:) convenience methods remain available.

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.

Artwork bounds and fitting

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.

Step 1 - initialize the SVG object

IJSVG* svg = [[IJSVG alloc] initWithFilePathURL:someURLHere];
// or with and without extension to find it within the bundle
IJSVG* svg = [IJSVG SVGNamed:@"my_svg"]; 

Step 2 - grab the NSImage from it

NSImage* svgImage = [svg imageWithSize:CGSizeMake(100.f,100.f)];

Other ways of drawing

IJSVG does allow you to directly draw the SVG into any focused drawing context for example within the drawRect of an NSView...

- (void)drawRect
{
  [svg drawInRect:self.bounds];
}

Helpers

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
};

Exporting

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.

SVG text

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];
NSImage* image = [svg imageWithSize:CGSizeMake(240, 80)];

IJSVG uses fonts installed on the system and falls back to another font if one is missing, so text can look different on another Mac. 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.

What it supports

  • Elements: svg, defs, 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 systemLanguage and requiredExtensions.
  • 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-origin and transform-box.
  • Stroking: stroke color and opacity, dash arrays and offsets, line caps, miter/round/bevel joins, miter limits, pathLength calibration and vector-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; auto uses sRGB.
  • Markers: marker, marker-start, marker-mid and marker-end on paths, lines, polylines and polygons. Supports custom child artwork, markerUnits, reference points, marker dimensions, viewBox, clipping, fixed angles, auto and auto-start-reverse orientation, and context-fill / context-stroke paints.
  • Color: named SVG colors, HEX, RGB(A), HSL(A), OKLCH and currentColor.
  • CSS: Embedded style sheets and inline styles, with type, class, ID and universal selectors, descendant and child combinators, and adjacent and general sibling combinators. Declaration resolution accounts for specificity, source order and !important.
  • CSS values and geometry: custom properties with var(), calc(), min(), max() and clamp() in supported length values, and CSS geometry properties. The media attribute on <style> supports media-query matching against the document viewport.
  • Context paints: context-fill and context-stroke in 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) and image-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, display and visibility.
  • 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 with inline-size.
  • Filters: feBlend, feColorMatrix, feComponentTransfer, feComposite, feConvolveMatrix, feDisplacementMap, feMorphology, feTile, feFlood, feOffset, feImage, feMerge, feGaussianBlur, feDropShadow, feTurbulence, feDiffuseLighting and feSpecularLighting.
  • Filter inputs: SourceGraphic, SourceAlpha, BackgroundImage, BackgroundAlpha, FillPaint, StrokePaint and named intermediate results.

Known limitations

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 attribute selectors and pseudo-classes are not supported. Stylesheet at-rules such as @media, @supports, @import and @font-face are not implemented; <style media="..."> is supported separately.
  • Fragment references such as href="#symbol" are supported, but external SVG document references such as href="icons.svg#symbol" are not resolved. Ordinary <image> loading does not currently resolve relative paths against the source document URL.
  • color-interpolation controls 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 by color-interpolation-filters.
  • SVG filter primitives are supported, but CSS filter functions such as filter: blur(4px) and filter: brightness(0.5) are not implemented.
  • <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 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.

Filter rendering and acceleration

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.

Credit

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.

About

MacOS SVG rendering and exporting library

Topics

Resources

Stars

176 stars

Watchers

13 watching

Forks

Releases

Packages

Used by

Contributors

Languages