Reputation: 1151
I have a .svg image file I want to display in my project.
I tried using UIImageView, which works for the .png & .jpg image formats, but not for the .svg extension. Is there any way to display a .svg image using UIWebView or UIImageView ?
Upvotes: 95
Views: 186456
Reputation: 5566
UIImage doesn't load the SVG with iOS17 natively.
macOS:
As of macOS 14.0 (Sonoma) the NSImage has native support for SVG images loading using Data or URL. Earlier macOS SDKs contain _NSSVGImageRep
(down to Catalina 10.15) but 14.0 is the first release that has this class registered (NSImageRep.registeredClasses
). However, the support for masks and CSS classes is still limited (10NOV2023).
Please note this is not documented and official. The representation is a private class _NSSVGImageRep
and you need CGImage to get bitmap data. Doesn't work with iOS16/iOS17.
let xmlSVGImage = "<svg width=\"195\" height=\"190\" xmlns=\"http://www.w3.org/2000/svg\"><polygon points=\"100,10 40,180 190,60 10,60 160,180\" style=\"fill:lime;stroke:purple;stroke-width:5;fill-rule:evenodd;\" /></svg>"
let svgData = xmlSVGImage.data(using: .utf8)!
let svgImage = NSImage(data: svgData)
print(svgImage)
Optional(<NSImage 0x600001400140 Size={185, 190} RepProvider=<NSImageArrayRepProvider: 0x600002704220, reps:(
"_NSSVGImageRep 0x60000063c1e0 Size={185, 190} ColorSpace=Generic RGB colorspace BPS=0 Pixels=0x0 Alpha=NO AppearanceName=(null)"
)>>)
To get scaled bitmap image:
var rect = NSRect(x: 0, y: 0, width: 1432, height: 1380)
let scaledCGImage = svgImage?.cgImage(forProposedRect: &rect, context: nil, hints: nil)
print(scaledCGImage)
Optional(<CGImage 0x124e058e0> (DP)
<<CGColorSpace 0x600000a512c0> (kCGColorSpaceICCBased; kCGColorSpaceModelRGB; Color LCD)>
width = 2864, height = 2760, bpc = 16, bpp = 64, row bytes = 22912
kCGImageAlphaPremultipliedLast | kCGImageByteOrder16Little | kCGImagePixelFormatPacked | kCGBitmapFloatComponents
is mask? No, has masking color? No, has soft mask? No, has matte? No, should interpolate? Yes)
Mind that secure archiving doesn't work. It will unarchive as bitmap.
let archivedData = try! NSKeyedArchiver.archivedData(withRootObject: svgImage!, requiringSecureCoding: true)
let unarchivedImage = try! NSKeyedUnarchiver.unarchivedObject(ofClass: NSImage.self, from: archivedData) as! NSImage
<NSImage 0x600003d04960 Size={185, 190} RepProvider=<NSImageArrayRepProvider: 0x600000e085b0, reps:(
"NSBitmapImageRep 0x6000027050a0 Size={185, 190} ColorSpace=(not yet loaded) BPS=8 BPP=(not yet loaded) Pixels=185x190 Alpha=YES Planar=NO Format=(not yet loaded) CurrentBacking=nil (faulting) CGImageSource=0x600000c2a400",
"NSBitmapImageRep 0x600002705880 Size={185, 190} ColorSpace=(not yet loaded) BPS=8 BPP=(not yet loaded) Pixels=370x380 Alpha=YES Planar=NO Format=(not yet loaded) CurrentBacking=nil (faulting) CGImageSource=0x600000c2a580",
"NSBitmapImageRep 0x6000027057a0 Size={185, 190} ColorSpace=(not yet loaded) BPS=8 BPP=(not yet loaded) Pixels=555x570 Alpha=YES Planar=NO Format=(not yet loaded) CurrentBacking=nil (faulting) CGImageSource=0x600000c2a880"
)>>
If you disable secure archiving/unarchiving you can get original SVGImageRep
let unsecureArchivedData = try! NSKeyedArchiver.archivedData(withRootObject: svgImage!, requiringSecureCoding: false)
let unsecureUnArchiver = try! NSKeyedUnarchiver(forReadingFrom: unsecureArchivedData)
unsecureUnArchiver.requiresSecureCoding = false
let decodedRoot = unsecureUnArchiver.decodeObject(forKey: "root") as? NSImage
Optional(<NSImage 0x600001094000 Size={185, 170} RepProvider=<NSImageArrayRepProvider: 0x6000023900d0, reps:(
"_NSSVGImageRep 0x600000294820 Size={185, 170} ColorSpace=Generic RGB colorspace BPS=0 Pixels=0x0 Alpha=NO AppearanceName=(null)"
)>>)
It's even possible to get SVG string using NSKeyedArchiver
+ NSKeyedUnarchiver
delegate method unarchiver:didDecodeObject:
. Look for NSMutableData
Even though _NSSVGImageRep is present in 10.15 etc, it is not in registered classes. It has started to be registered on Sonoma
let registeredClasses = NSImageRep.registeredClasses
print(registeredClasses)
[NSBitmapImageRep, NSPICTImageRep, NSPDFImageRep, _NSSVGImageRep, NSEPSImageRep]
(lldb)
Upvotes: 1
Reputation: 7991
Since XCode 12, it is possible to add SVG assets to your project.
To add svg file to your project:
Scales
property to Single Scale
in attributes inspector.Upvotes: 8
Reputation: 41
Here is objective c solution
- (void)loadSVG:(NSString *)url {
if (url.length == 0) return;
[[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:url]
completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSHTTPURLResponse *httpURLResponse = (NSHTTPURLResponse *) response;
if (error == nil && [response.MIMEType hasPrefix:@"image"] && httpURLResponse.statusCode == 200)
{
SVGKImage *receivedIcon = [SVGKImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
imageView.backgroundColor = [UIColor clearColor];
imageView.image = receivedIcon.UIImage;
});
} else {
NSLog(@"error %@ ", error.localizedDescription);
}
}] resume];
}
Upvotes: 0
Reputation: 471
SVGKit helped me on getting the image from URL.
First, add pod 'SVGKit'
in your Podfile.
Second, import SVGKit
into your class.
Third, create an object of SVGImage.
let mySVGImage: SVGKImage = SVGKImage(contentsOf: URL(string: path))
Finally, add this image to your UIImageView.
yourImageView.image = mySVGImage.uiImage
Upvotes: 5
Reputation: 377
My solution to show .svg in UIImageView from URL. You need to install SVGKit pod
Then just use it like this:
import SVGKit
let svg = URL(string: "https://openclipart.org/download/181651/manhammock.svg")!
let data = try? Data(contentsOf: svg)
let receivedimage: SVGKImage = SVGKImage(data: data)
imageview.image = receivedimage.uiImage
or you can use extension for async download
extension UIImageView {
func downloadedsvg(from url: URL, contentMode mode: UIView.ContentMode = .scaleAspectFit) {
contentMode = mode
URLSession.shared.dataTask(with: url) { data, response, error in
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
let data = data, error == nil,
let receivedicon: SVGKImage = SVGKImage(data: data),
let image = receivedicon.uiImage
else { return }
DispatchQueue.main.async() {
self.image = image
}
}.resume()
}
}
How to use:
let svg = URL(string: "https://openclipart.org/download/181651/manhammock.svg")!
imageview.downloadedsvg(from: svg)
Upvotes: 21
Reputation: 21
As I know there are 2 different graphic formats:
So if you need to use an image stored in SVG File in your Xcode I would suggest:
Convert SVG file to PDF. I used https://document.online-convert.com/convert/svg-to-pdf
Use Xcode to manage you PDF file.
Upvotes: 2
Reputation: 503
To render SVG file you can use Macaw. Also Macaw supports transformations, user events, animation and various effects.
You can render SVG file with zero lines of code. For more info please check this article: Render SVG file with Macaw.
DISCLAIMER: I am affiliated with this project.
Upvotes: 2
Reputation: 1225
You can add New Symbol Image Set in .xcassets, then you can add SVG file in it
and use it same like image.
Note: This doesn't work on all SVG. You can have a look at the apple documentation
Upvotes: 17
Reputation: 1
You can use this pod called 'SVGParser'. https://cocoapods.org/pods/SVGParser.
After adding it in your pod file, all you have to do is to import this module to the class that you want to use it. You should show the SVG image in an ImageView.
There are three cases you can show this SVGimage:
You can also find an example project in GitHub: https://github.com/AndreyMomot/SVGParser. Just download the project and run it to see how it works.
Upvotes: 0
Reputation: 38239
let path = Bundle.main.path(forResource: "svgNameFileHere", ofType: "svg")!
if path != "" {
let fileURL:URL = URL(fileURLWithPath: path)
let req = URLRequest(url: fileURL)
self.webView.scalesPageToFit = false
self.webView.loadRequest(req)
}
else {
//handle here if path not found
}
Third party libraries
https://github.com/exyte/Macaw
https://github.com/mchoe/SwiftSVG
UIWebView and WKWebView booster to load faster
https://github.com/bernikovich/WebViewWarmUper
Upvotes: 11
Reputation: 950
In case you want to use a WKWebView
to load a .svg image that is coming from a URLRequest
, you can simply achieve it like this:
Swift 4
if let request = URLRequest(url: urlString), let svgString = try? String(contentsOf: request) {
wkWebView.loadHTMLString(svgString, baseURL: request)
}
It's much simpler than the other ways of doing it, and you can also persist your .svg string somewhere to load it later, even offline if you need to.
Upvotes: 9
Reputation: 5340
There is no Inbuilt support for SVG in Swift. So we need to use other libraries.
The simple SVG libraries in swift are :
1) SwiftSVG Library
It gives you more option to Import as UIView, CAShapeLayer, Path, etc
To modify your SVG Color and Import as UIImage you can use my extension codes for the library mentioned in below link,
Click here to know on using SwiftSVG library :
Using SwiftSVG to set SVG for Image
|OR|
2) SVGKit Library
2.1) Use pod to install :
pod 'SVGKit', :git => 'https://github.com/SVGKit/SVGKit.git', :branch => '2.x'
2.2) Add framework
Goto AppSettings
-> General Tab
-> Scroll down to Linked Frameworks and Libraries
-> Click on plus icon
-> Select SVG.framework
2.3) Add in Objective-C to Swift bridge file bridging-header.h :
#import <SVGKit/SVGKit.h>
#import <SVGKit/SVGKImage.h>
2.4) Create SvgImg Folder (for better organization) in Project and add SVG files inside it.
Note : Adding Inside Assets Folder won't work and SVGKit searches for file only in Project folders
2.5) Use in your Swift Code as below :
import SVGKit
and
let namSvgImgVar: SVGKImage = SVGKImage(named: "NamSvgImj")
Note : SVGKit Automatically apends extention ".svg" to the string you specify
let namSvgImgVyuVar = SVGKImageView(SVGKImage: namSvgImgVar)
let namImjVar: UIImage = namSvgImgVar.UIImage
There are many more options for you to init SVGKImage and SVGKImageView
There are also other classes u can explore
SVGRect
SVGCurve
SVGPoint
SVGAngle
SVGColor
SVGLength
and etc ...
Upvotes: 25
Reputation: 1773
Here's a simple class that can display SVG images in a UIView
import UIKit
public class SVGImageView: UIView {
private let webView = UIWebView()
public init() {
super.init(frame: .zero)
webView.delegate = self
webView.scrollView.isScrollEnabled = false
webView.contentMode = .scaleAspectFit
webView.backgroundColor = .clear
addSubview(webView)
webView.snp.makeConstraints { make in
make.edges.equalTo(self)
}
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
webView.stopLoading()
}
public func load(url: String) {
webView.stopLoading()
if let url = URL(string: fullUrl) {
webView.loadRequest(URLRequest(url: url))
}
}
}
extension SVGImageView: UIWebViewDelegate {
public func webViewDidFinishLoad(_ webView: UIWebView) {
let scaleFactor = webView.bounds.size.width / webView.scrollView.contentSize.width
if scaleFactor <= 0 {
return
}
webView.scrollView.minimumZoomScale = scaleFactor
webView.scrollView.maximumZoomScale = scaleFactor
webView.scrollView.zoomScale = scaleFactor
}
}
Upvotes: 4
Reputation: 1414
You can keep your images as strings and use WKWebView to display them:
let webView: WKWebView = {
let mySVGImage = "<svg height=\"190\"><polygon points=\"100,10 40,180 190,60 10,60 160,180\" style=\"fill:lime;stroke:purple;stroke-width:5;fill-rule:evenodd;\"></svg>"
let preferences = WKPreferences()
preferences.javaScriptEnabled = false
let configuration = WKWebViewConfiguration()
configuration.preferences = preferences
let wv = WKWebView(frame: .zero, configuration: configuration)
wv.scrollView.isScrollEnabled = false
wv.loadHTMLString(mySVGImage, baseURL: nil)
return wv
}()
Upvotes: 7
Reputation: 4437
You can use SVGKit for example.
1) Integrate it according to instructions. Drag&dropping the .framework file is fast and easy.
2) Make sure you have an Objective-C to Swift bridge file bridging-header.h with import code in it:
#import <SVGKit/SVGKit.h>
#import <SVGKit/SVGKImage.h>
3) Use the framework like this, assuming that dataFromInternet is NSData, previously downloaded from network:
let anSVGImage: SVGKImage = SVGKImage(data: dataFromInternet)
myIUImageView.image = anSVGImage.UIImage
The framework also allows to init an SVGKImage from other different sources, for example it can download image for you when you provide it with URL. But in my case it was crashing in case of unreachable url, so it turned out to be better to manage networking by myself. More info on it here.
Upvotes: 17
Reputation: 422
Try this code
var path: String = NSBundle.mainBundle().pathForResource("nameOfFile", ofType: "svg")!
var url: NSURL = NSURL.fileURLWithPath(path) //Creating a URL which points towards our path
//Creating a page request which will load our URL (Which points to our path)
var request: NSURLRequest = NSURLRequest(URL: url)
webView.loadRequest(request) //Telling our webView to load our above request
Upvotes: 17