▶hlongvu

How to Download and Display SVG Image in Swift IOS App by Kingfisher

When working with images in an iOS app, we often have to download and display remote image from the internet. There are many great libraries out there help us do this really simple. I myself choose Kingfisher as the library to go because it is a modern, lightweight and pure-Swift library.

Kingfisher helped me to display and cache almost every typical image format we want. But with SVG image, we need to do a little bit more. We have to manually decode SVG into image data with a Processor.

We do this with a little help from PocketSVG library:

import Kingfisher
import PocketSVG

struct SVGProcessor: ImageProcessor {
    
    // `identifier` should be the same for processors with the same properties/functionality
    // It will be used when storing and retrieving the image to/from cache.
    let identifier = "svgprocessor"
    var size: CGSize!
    init(size: CGSize) {
        self.size = size
    }
    // Convert input data/image to target image and return it.
    func process(item: ImageProcessItem, options: KingfisherParsedOptionsInfo) -> Image? {
        switch item {
        case .image(let image):
//            print("already an image")
            return image
        case .data(let data):
//            print("svg string")
            if let svgString = String(data: data, encoding: .utf8){
                //let layer = SVGLayer(
                let path = SVGBezierPath.paths(fromSVGString: svgString)
                let layer = SVGLayer()
                layer.paths = path
                let frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
                layer.frame = frame
                let img = self.snapshotImage(for: layer)
                return img
            }
            return nil
        }
    }
    func snapshotImage(for view: CALayer) -> UIImage? {
        UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, UIScreen.main.scale)
        guard let context = UIGraphicsGetCurrentContext() else { return nil }
        view.render(in: context)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
}

Then we can use this processor like this:

 let svgUrl = URL(string: "http://svg_image_url")!        
        let processor = SVGProcessor(size: CGSize(width: 240, height: 43))
        KingfisherManager.shared.retrieveImage(with: svgUrl, options: [.processor(processor), .forceRefresh]) {  result in
                switch (result){
                    case .success(let value):
                        myImageView.image = value.image
                    case .failure(let error):
                        print("error", error.localizedDescription)
                }
        }

Now we can use nice and clean Kingfisher API with our SVG image.