Skip to content

Instantly share code, notes, and snippets.

@armstrongnate
Created January 12, 2023 22:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save armstrongnate/7df55f6d47d7e71e8feb390278416936 to your computer and use it in GitHub Desktop.
Save armstrongnate/7df55f6d47d7e71e8feb390278416936 to your computer and use it in GitHub Desktop.
Render SVG from data in swift
private func imageFrom(url: URL?, data: Data, response: HTTPURLResponse? = nil) -> AnyPublisher<UIImage?, Error> {
let type = response?.mimeType
if type?.hasPrefix("image/svg") == true || url?.pathExtension.lowercased() == "svg" {
return svgFrom(data: data)
}
return Just(UIImage(data: data)).setFailureType(to: Error.self).eraseToAnyPublisher()
}
private func svgFrom(data: Data) -> AnyPublisher<UIImage?, Error> {
let dataUri = "data:image/svg+xml;base64,\(data.base64EncodedString())"
let html = """
<!doctype html>
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
<style>*{margin:0;padding:0;height:100%;width:100%;}</style>
<img src="\(dataUri)" style="object-position:center;object-fit:contain;"
onload="setTimeout(()=>webkit.messageHandlers.svg.postMessage(''),17)"
/>
"""
return Future { promise in
DispatchQueue.main.async {
let config = WKWebViewConfiguration()
config.websiteDataStore = .nonPersistent()
var webView: WKWebView? = WKWebView(frame: CGRect(x: 0, y: 0, width: 24, height: 24), configuration: config)
webView?.backgroundColor = .clear
webView?.isOpaque = false
webView?.loadHTMLString(html, baseURL: nil)
webView?.handle("svg") { _ in
webView?.takeSnapshot(with: nil) { snapshot, error in
webView = nil
if let error = error {
promise(.failure(error))
} else {
promise(.success(snapshot))
}
}
}
}
}
.eraseToAnyPublisher()
}
typealias MessageHandler = (WKScriptMessage) -> Void
extension WKWebView {
func handle(_ name: String, handler: @escaping MessageHandler) {
let passer = MessagePasser(handler: handler)
configuration.userContentController.removeScriptMessageHandler(forName: name)
configuration.userContentController.add(passer, name: name)
}
}
private class MessagePasser: NSObject, WKScriptMessageHandler {
let handler: MessageHandler
init(handler: @escaping MessageHandler) {
self.handler = handler
super.init()
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
handler(message)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment