SwiftDraw displays SVG images natively in SwiftUI, UIKit and AppKit. It includes a pure-Swift SVG parser and renderer, plus a command-line tool for converting SVGs to PNG, PDF, custom SF Symbols and Swift source code.
SVGView works much like SwiftUI’s built-in Image view:
import SwiftDraw
SVGView("sample.svg")By default, the SVG is rendered at its intrinsic size. To make it flexible within layouts, mark it as resizable:
SVGView("sample.svg").resizable().scaledToFit()SVGView works just like Image:
.scaledToFit()to scale proportionally so the SVG fits inside its container..scaledToFill()to fill the entire container, cropping if necessary..resizable(resizingMode: .tile)to repeat the SVG as tiles across the available space.
SVGs can also be rendered as templates, replacing every non-transparent pixel with the current foreground style:
SVGView("spider.svg").renderingMode(.template).foregroundStyle(LinearGradient(
colors:[.blue,.purple],
startPoint:.topLeading,
endPoint:.bottomTrailing
)).original | .template |
|---|---|
![]() | ![]() |
When loading by name, SVGView maintains an internal cache for efficient repeated lookups.
For more predictable performance (avoiding cache lookups or parsing), you can pass in an already-constructed SVG instance:
varimage:SVGvarbody:someView{SVGView(svg: image)}Remote SVGs can be loaded using AsyncSVGView:
AsyncSVGView(url:URL(string:"https://example.com/image.svg")).resizable().scaledToFit()For custom loading and error states, use the phase-based initializer:
AsyncSVGView(url: url){ phase inswitch phase {case.empty:ProgressView()case.success(let svg):SVGView(svg: svg)case.failure:Image(systemName:"exclamationmark.triangle")}}SVG images can be loaded and rasterized to UIImage or NSImage:
letsvg=SVG(named:"sample.svg", in:.main)!
imageView.image = svg.rasterize()Transformations can be added before rasterizing:
letsvg=SVG(named:"fish.svg")! // 100x100
.expanded(left:10, right:10) // 120x100
.scaled(2) // 240x200
imageView.image = svg.rasterize() // 240x200Create a UIImage directly from an SVG within a bundle, Data or file URL:
import SwiftDraw
letimage=UIImage(svgNamed:"sample.svg")Create an NSImage directly from an SVG within a bundle, Data or file URL:
import SwiftDraw
letimage=NSImage(svgNamed:"sample.svg")The command line tool converts SVGs to other formats: PNG, JPEG, SFSymbol and Swift source code.
copyright (c) 2026 Simon Whitty
usage: swiftdraw <file.svg> [--format png | pdf | jpeg | swift | sfsymbol] [--size wxh] [--scale 1x | 2x | 3x]
<file> svg file to be processed
Options:
--format format to output image: png | pdf | jpeg | swift | sfsymbol
--size size of output image: 100x200
--scale scale of output image: 1x | 2x | 3x
--insets crop inset of output image: top,left,bottom,right
--precision maximum number of decimal places
--output optional path of output file
--hide-unsupported-filters hide elements with unsupported filters.
Available keys for --format swift:
--api api of generated code: swiftui | appkit | uikit
Available keys for --format sfsymbol:
--insets alignment of regular variant: top,left,bottom,right | auto
--size size category to generate: small, medium large. (default is small)
--ultralight svg file of ultralight variant
--ultralight-insets alignment of ultralight variant: top,left,bottom,right | auto
--ultralight-stroke-width auto-generate ultralight variant by scaling regular stroke-width: 0.5 | 50%
--black svg file of black variant
--black-insets alignment of black variant: top,left,bottom,right | auto
--black-stroke-width auto-generate black variant by scaling regular stroke-width: 2.0 | 200%
--legacy use the original, less precise alignment logic from earlier swiftdraw versions.
$ swiftdraw simple.svg --format png --scale 3x$ swiftdraw simple.svg --format pdfWhen the root <svg> uses percent values (width="100%") or omits width/height entirely, SwiftDraw cannot determine the canvas size from the file alone. In those cases provide an explicit canvas size with --size, which acts as the viewport that percent values resolve against and as a fallback when both width/height and viewBox are missing:
$ swiftdraw responsive.svg --format png --size 800x600If the SVG already declares a viewBox, missing width/height fall back to its dimensions automatically and --size is not required.
You can install the swiftdraw command-line tool on macOS using Homebrew. Assuming you already have Homebrew installed, just type:
$ brew install swiftdrawTo update to the latest version once installed:
$ brew upgrade swiftdrawAlternatively download the latest command line tool here.
Custom SF Symbols can be created from a single SVG. SwiftDraw expands strokes, winds paths using the non-zero rule and aligns elements generating a symbol that can be imported directly into Xcode.
$ swiftdraw key.svg --format sfsymbol
Optional variants --ultralight and --black can also be provided:
$ swiftdraw key.svg --format sfsymbol --ultralight key-ultralight.svg --black key-black.svg
By default, SwiftDraw automatically sizes and aligns the content to the template guides. The auto alignment insets are output by the tool:
$ swiftdraw simple.svg --format sfsymbol --insets auto
Alignment: --insets 30,30,30,30Insets can be provided in the form --insets top,left,bottom,right specifying a Double or auto for each edge:
$ swiftdraw simple.svg --format sfsymbol --insets 40,auto,40,auto
Alignment: --insets 40,30,40,30Variants can also be aligned using --ultralightInsets and --blackInsets.
When matching ultralight or black SVGs are not available, SwiftDraw can synthesize them from the regular SVG by scaling every stroke-width value before strokes are expanded. Both decimal and percent forms are accepted:
$ swiftdraw key.svg --format sfsymbol \
--ultralight-stroke-width 50% \
--black-stroke-width 2.0Notes:
- An explicit
--ultralightor--blackSVG always wins over the matching--*-stroke-widthflag. A warning is printed if both are supplied. - The scaler walks element attributes, inline styles, and
<style>rules. If the regular SVG has nostroke-widthvalues to scale, a warning is printed and the regular paths are reused unchanged. - Only
stroke-widthis scaled today. Future work could add scaling for related attributes (for example, dash arrays).
Swift source code can also be generated from an SVG using the tool:
$ swiftdraw simple.svg --format swift<?xml version="1.0" encoding="utf-8"?>
<svgversion="1.1"xmlns="http://www.w3.org/2000/svg"width="160"height="160">
<rectwidth="160"height="160"fill="snow" />
<pathd="m 80 30 a 50 50 0 1 0 50 50 h -50 z"fill="pink"stroke="black"stroke-width="2"/>
</svg>structSimpleView:View{varbody:someView{if isResizable {
canvas
.frame(idealWidth:160.0, idealHeight:160.0)}else{
canvas
.frame(width:160.0, height:160.0)}}privatevarisResizable=falsefunc resizable()->Self{varcopy=self copy.isResizable =truereturn copy
}varcanvas:someView{Canvas(
opaque:false,
colorMode:.linear,
rendersAsynchronously:false){ context, size inletscale=CGSize(width: size.width /160.0, height: size.height /160.0) context.withCGContext{ ctx in
ctx.scaleBy(x: scale.width, y: scale.height)letrgb=CGColorSpaceCreateDeviceRGB()letcolor1=CGColor(colorSpace: rgb, components:[1,0.98,0.98,1])!
ctx.setFillColor(color1)
ctx.fill(CGRect(x:0, y:0, width:160, height:160))letcolor2=CGColor(colorSpace: rgb, components:[1,0.753,0.796,1])!
ctx.setFillColor(color2)letpath=CGMutablePath()
path.move(to:CGPoint(x:80, y:30))
path.addCurve(to:CGPoint(x:30, y:80),
control1:CGPoint(x:52.39, y:30),
control2:CGPoint(x:30, y:52.39))
path.addCurve(to:CGPoint(x:80, y:130),
control1:CGPoint(x:30, y:107.61),
control2:CGPoint(x:52.39, y:130))
path.addCurve(to:CGPoint(x:130, y:80),
control1:CGPoint(x:107.61, y:130),
control2:CGPoint(x:130, y:107.61))
path.addLine(to:CGPoint(x:80, y:80))
path.closeSubpath()
ctx.addPath(path)
ctx.fillPath()
ctx.setLineCap(.butt)
ctx.setLineJoin(.miter)
ctx.setLineWidth(2)
ctx.setMiterLimit(4)letcolor3=CGColor(colorSpace: rgb, components:[0,0,0,1])!
ctx.setStrokeColor(color3)
ctx.addPath(path)
ctx.strokePath()}}}}Source code can be generated using www.whileloop.com/swiftdraw.
SwiftDraw is primarily the work of Simon Whitty.

