-
-
Save ollieatkinson/eb87a82fcb5500d5561fed8b0900a9f7 to your computer and use it in GitHub Desktop.
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) | |
} | |
} | |
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?
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, 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.
it's possible if you use this and apply the tint inside CGContext