Skip to content

Instantly share code, notes, and snippets.

@ollieatkinson
Last active June 27, 2026 03:45
Show Gist options
  • Select an option

  • Save ollieatkinson/eb87a82fcb5500d5561fed8b0900a9f7 to your computer and use it in GitHub Desktop.

Select an option

Save ollieatkinson/eb87a82fcb5500d5561fed8b0900a9f7 to your computer and use it in GitHub Desktop.
Utilise the private CoreSVG framework in Swift
import Darwin
import Foundation
import UIKit
// https://github.com/xybp888/iOS-SDKs/blob/master/iPhoneOS17.1.sdk/System/Library/PrivateFrameworks/CoreSVG.framework/CoreSVG.tbd
// https://developer.limneos.net/index.php?ios=17.1&framework=UIKitCore.framework&header=UIImage.h
@objc
class CGSVGDocument: NSObject { }
var CGSVGDocumentRetain: (@convention(c) (CGSVGDocument?) -> Unmanaged<CGSVGDocument>?) = load("CGSVGDocumentRetain")
var CGSVGDocumentRelease: (@convention(c) (CGSVGDocument?) -> Void) = load("CGSVGDocumentRelease")
var CGSVGDocumentCreateFromData: (@convention(c) (CFData?, CFDictionary?) -> Unmanaged<CGSVGDocument>?) = load("CGSVGDocumentCreateFromData")
var CGContextDrawSVGDocument: (@convention(c) (CGContext?, CGSVGDocument?) -> Void) = load("CGContextDrawSVGDocument")
var CGSVGDocumentGetCanvasSize: (@convention(c) (CGSVGDocument?) -> CGSize) = load("CGSVGDocumentGetCanvasSize")
typealias ImageWithCGSVGDocument = @convention(c) (AnyObject, Selector, CGSVGDocument) -> UIImage
var ImageWithCGSVGDocumentSEL: Selector = NSSelectorFromString("_imageWithCGSVGDocument:")
let CoreSVG = dlopen("/System/Library/PrivateFrameworks/CoreSVG.framework/CoreSVG", RTLD_NOW)
func load<T>(_ name: String) -> T {
unsafeBitCast(dlsym(CoreSVG, name), to: T.self)
}
public class SVG {
deinit { CGSVGDocumentRelease(document) }
let document: CGSVGDocument
public convenience init?(_ value: String) {
guard let data = value.data(using: .utf8) else { return nil }
self.init(data)
}
public init?(_ data: Data) {
guard let document = CGSVGDocumentCreateFromData(data as CFData, nil)?.takeUnretainedValue() else { return nil }
guard CGSVGDocumentGetCanvasSize(document) != .zero else { return nil }
self.document = document
}
public var size: CGSize {
CGSVGDocumentGetCanvasSize(document)
}
public func image() -> UIImage? {
let ImageWithCGSVGDocument = unsafeBitCast(UIImage.self.method(for: ImageWithCGSVGDocumentSEL), to: ImageWithCGSVGDocument.self)
let image = ImageWithCGSVGDocument(UIImage.self, ImageWithCGSVGDocumentSEL, document)
return image
}
public func draw(in context: CGContext) {
draw(in: context, size: size)
}
public func draw(in context: CGContext, size target: CGSize) {
var target = target
let ratio = (
x: target.width / size.width,
y: target.height / size.height
)
let rect = (
document: CGRect(origin: .zero, size: size), ()
)
let scale: (x: CGFloat, y: CGFloat)
if target.width <= 0 {
scale = (ratio.y, ratio.y)
target.width = size.width * scale.x
} else if target.height <= 0 {
scale = (ratio.x, ratio.x)
target.width = size.width * scale.y
} else {
let min = min(ratio.x, ratio.y)
scale = (min, min)
target.width = size.width * scale.x
target.height = size.height * scale.y
}
let transform = (
scale: CGAffineTransform(scaleX: scale.x, y: scale.y),
aspect: CGAffineTransform(translationX: (target.width / scale.x - rect.document.width) / 2, y: (target.height / scale.y - rect.document.height) / 2)
)
context.translateBy(x: 0, y: target.height)
context.scaleBy(x: 1, y: -1)
context.concatenate(transform.scale)
context.concatenate(transform.aspect)
CGContextDrawSVGDocument(context, document)
}
}
@thomasalbert1993

Copy link
Copy Markdown

Do you know why applying .withRenderingMode(.alwaysTemplate) to rendered image (mySVG.image()) does not work?
I'm not able to tint my SVG icons this way, whereas it works when I import them in a .xcassets file 🤔

@ollieatkinson

Copy link
Copy Markdown
Author

template mode only works from assets taken from xcasset file, unsure of the exact reason - possibly due to how they are loaded and can be masked. To work around this you can mask a color with the SVG.

@ollieatkinson

Copy link
Copy Markdown
Author

Personally, I use the svg.draw(in: context, size: rect.size) method so I can directly apply fill mode in CGContext.

@thomasalbert1993

Copy link
Copy Markdown

Thanks for your answer! Yes I managed to re-color the SVG but I wanted to take advantage of UIImageView.tintColor which grays icon when view is not in focus, but it seems not to be doable this way with SVGs. Too bad..

@ollieatkinson

Copy link
Copy Markdown
Author

it's possible if you use this and apply the tint inside CGContext

@Eggers-CGI

Copy link
Copy Markdown

Hey, nice gist :-) I see for each SVG rendered a "CGGStackRestore: CG GState restored too many times" - do you experience the same? Am i doing something wrong?

@ollieatkinson

Copy link
Copy Markdown
Author

Hey, nice gist :-) I see for each SVG rendered a "CGGStackRestore: CG GState restored too many times" - do you experience the same? Am i doing something wrong?

Does this happen with every SVG? are you in a SwiftUI or UIKit context?

@Eggers-CGI

Copy link
Copy Markdown

Hey, nice gist :-) I see for each SVG rendered a "CGGStackRestore: CG GState restored too many times" - do you experience the same? Am i doing something wrong?

Does this happen with every SVG? are you in a SwiftUI or UIKit context?

Hey - every SVG I tested at least. SwiftUI. But no worries, a different approach is working now for me :-) SDWebImage has to do this now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment