8

With Xcode 12 release, now SVG assets are supported.

It is fine if I want to use SVG in my asset catalog. But it doesn't work when I try to load it from an URL any idea?

let downloadURL = URL.init(string:"https://www.flaticon.com/svg/static/icons/svg/3874/3874453.svg")
image.af.setImage(withURL: downloadURL!,imageTransition: .crossDissolve(0.5))
Murat Akdeniz
  • 424
  • 5
  • 7
  • There's a huge difference between an SVG asset and one downloaded from a URL. You'll likely need to (1) download the SVG, then (2) convert it into a UIImage (probably in a background thread). Assets are (at least) normally meant to be a **part** of an app package. Who knows what `UIKit` or `SwiftUI` methods are used to turn an asset into a `UIImage`? Keep in mind, there are also other kinds of assets - UIColor, for instance. –  Dec 12 '20 at 15:58

2 Answers2

8

First, your description of the frameworks you'd like to use is very unclear. It's hard to imagine what image.af.setImage is.
There're third-party frameworks which support SVG, e.g. https://github.com/mchoe/SwiftSVG.
But I assume you're interested in SDK solutions.

Second, you should define what to you mean by "asset". Generally, in Xcode an asset is a resource file build into app, so there's no need to download it from URL.

1. You can easily load an SVG with WebKit:

let path = "https://www.flaticon.com/svg/static/icons/svg/3874/3874453.svg"
let webView = WKWebView(frame: view.bounds)
let request = URLRequest(url: URL(string: path)!)
webView.load(request)
view.addSubview(webView)

2. If you're considering a framework other than WebKit, you can load that image as Data, and then pass that Data to your framework:

let path = "https://www.flaticon.com/svg/static/icons/svg/3874/3874453.svg"
let data = try! Data(contentsOf: URL(string: path)!)

3. You can save an SVG as a "resource", and load that local resource. This is the optimal way.

let path = Bundle.main.path(forResource: "3874453", ofType: "svg")!
let webView = WKWebView(frame: view.bounds)
let request = URLRequest(url: URL(fileURLWithPath: path)!)
webView.load(request)
view.addSubview(webView)

The full code looks like this:

import UIKit
import WebKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let webView = WKWebView(frame: view.bounds)
        let request = URLRequest(url: svgUrlLocal)
        //let request = URLRequest(url: svgUrlRemote)
        webView.load(request)
        view.addSubview(webView)
    }
    
    var svgUrlLocal: URL {
        let path = Bundle.main.path(forResource: "3874453", ofType: "svg")!
        return URL(fileURLWithPath: path)
    }
    
    var svgUrlRemote: URL {
        let path = "https://www.flaticon.com/svg/static/icons/svg/3874/3874453.svg"
        return URL(string: path)!
    }
}

You can download the project here: https://github.com/gatamar/stackoverflow_answers/tree/master/so65266899

olha
  • 2,132
  • 1
  • 18
  • 39
  • I would like to thank you for the effort. It seems it is not that easy to use SVG as UIImge. I really appreciate your answer. Great! – Murat Akdeniz Dec 12 '20 at 21:30
  • 1
    @MuratAkdeniz Well, if you want to use SVG in a UIImageView, here they explain how you can load SVG to UIImage: just add an SVG to assets, them use `UIImage(named`: https://developer.apple.com/forums/thread/72838 – olha Dec 13 '20 at 13:29
  • @olha I want to resize the SVG image to fit in WKWebView. How can I do this? I have tried many different solutions but have not been able to do it. – NightWatcher Jan 23 '23 at 09:33
  • @NightWatcher please post a question of what you've tried and what you want to achieve. You may also put a link to that question here – olha Jan 23 '23 at 20:10
0

Actually, we can use a web view to create a UIImage from SVG data. This class has been thoroughly tested and works exceptionally well.

This line of code will demonstrate how easy it is to use.

Data is an SVG data. URL is the server URL of the SVG. It is optional.

SVGLoader.load(data: data, url: urlS) { image in
                       
 }

import Foundation
import WebKit

class SVGLoader {
    typealias wkType = (data: Data, complition: ((UIImage?) -> Void)?, url: String?)
    static var wkContainer = [wkType]()
    static var wView: WKView?
    static func load(data: Data, url: String?, size: CGSize = CGSize(width: 600, height: 600), complition: @escaping ((UIImage?) -> Void)) {
        let wkData: wkType = (data, complition, url)
        wkContainer.append(wkData)
        if wView == nil {
            wView = WKView(frame: CGRect(origin: .zero, size: size))
        }
    }
    
    static func clean() {
        if wkContainer.isEmpty {
            wView = nil
        }
    }
    
    class WKView: NSObject, WKNavigationDelegate
    {
        var webKitView: WKWebView?
        init(frame: CGRect) {
            super.init()
            webKitView = WKWebView(frame: frame)
            webKitView?.navigationDelegate = self
            webKitView?.isOpaque = false
            webKitView?.backgroundColor = .clear
            webKitView?.scrollView.backgroundColor = .clear
            loadData()
        }
        
        
        func loadData() {
            let datas = SVGLoader.wkContainer
            if datas.isEmpty {
                return
            }
            guard let data = datas.first?.data else {
                return
            }
            let urlS = datas.first?.url ?? ""
            let url = URL(string: urlS) ?? (NSURL(string: "")! as URL)
            webKitView?.load(data, mimeType: "image/svg", characterEncodingName: "", baseURL: url)
        }
        
        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            webView.takeSnapshot(with: nil) { [weak self] image, error in
                wkContainer.first?.complition?(image)
                wkContainer.removeFirst()
                self?.loadData()
                clean()
            }
        }
    }
}
Arsen Avetisyan
  • 171
  • 2
  • 4