UIImage.gif(name: "imageName") imageView.loadGif(name: "imageName")
//
// https://github.com/bahlo/SwiftGif
//
//
// Created by Jim Du on 11/07/2017.
// Copyright © 2017 Jim Du. All rights reserved.
//
import UIKit
import ImageIO
extension UIImage {
public class func gif(data: Data) -> UIImage? {
guard let source = CGImageSourceCreateWithData(data as CFData, nil) else {
print("UIImageGif: Source for the image does not exist")
return nil
}
return UIImage.animatedImageWithSource(source)
}
public class func gif(url: String) -> UIImage? {
guard let bundleURL = URL(string: url) else {
print("UIImageGif: This image named \"\(url)\" does not exist")
return nil
}
guard let imageData = try? Data(contentsOf: bundleURL) else {
print("UIImageGif: Cannot turn image named \"\(url)\" into NSData")
return nil
}
return gif(data: imageData)
}
public class func gif(name: String) -> UIImage? {
guard let bundleURL = Bundle.main.url(forResource: name, withExtension: "gif") else {
print("UIImageGif: This image named \"\(name)\" does not exist")
return nil
}
guard let imageData = try? Data(contentsOf: bundleURL) else {
print("UIImageGif: Cannot turn image named \"\(name)\" into NSData")
return nil
}
return gif(data: imageData)
}
internal class func delayForImageAtIndex(_ index: Int, source: CGImageSource!) -> Double {
var delay = 0.1
// Get dictionaries
let cfProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil)
let gifPropertiesPointer = UnsafeMutablePointer<UnsafeRawPointer?>.allocate(capacity: 0)
guard CFDictionaryGetValueIfPresent(cfProperties, Unmanaged.passUnretained(kCGImagePropertyGIFDictionary).toOpaque(), gifPropertiesPointer) else {
return delay
}
let gifProperties: CFDictionary = unsafeBitCast(gifPropertiesPointer.pointee, to: CFDictionary.self)
// Get delay time
var delayObject = unsafeBitCast(CFDictionaryGetValue(gifProperties, Unmanaged.passUnretained(kCGImagePropertyGIFUnclampedDelayTime).toOpaque()), to: AnyObject.self)
if delayObject.doubleValue == 0 {
delayObject = unsafeBitCast(CFDictionaryGetValue(gifProperties, Unmanaged.passUnretained(kCGImagePropertyGIFDelayTime).toOpaque()), to: AnyObject.self)
}
delay = delayObject as? Double ?? 0
return max(delay, 0.1) // Make sure they're not too fast
}
internal class func gcdForPair(_ left: Int?, _ right: Int?) -> Int {
// Check if one of them is nil
guard var a = right, var b = left else {
return right ?? left ?? 0
}
// Get greatest common divisor
var rest: Int
while true {
rest = a % b
if rest == 0 {
return b
}
a = b
b = rest
}
}
internal class func animatedImageWithSource(_ source: CGImageSource) -> UIImage? {
let count = CGImageSourceGetCount(source)
var images = [CGImage]()
var delays = [Int]()
// Fill arrays
for i in 0..<count {
// Add image
if let image = CGImageSourceCreateImageAtIndex(source, i, nil) {
images.append(image)
}
// At it's delay in cs
let delaySeconds = UIImage.delayForImageAtIndex(i, source: source)
delays.append(Int(delaySeconds * 1000.0)) // Seconds to ms
}
// Calculate full duration
let duration = delays.reduce(0, { $0 + $1 })
// Get frames
let gcd = delays.isEmpty ? 1 : delays.reduce(delays[0], { UIImage.gcdForPair($1, $0) })
var frames = [UIImage]()
var frame: UIImage
for i in 0..<count {
frame = UIImage(cgImage: images[Int(i)])
for _ in 0..<Int(delays[i] / gcd) {
frames.append(frame)
}
}
return UIImage.animatedImage(with: frames, duration: Double(duration) / 1000.0)
}
}
extension UIImageView {
public func loadGif(name: String) {
DispatchQueue.global().async {
let image = UIImage.gif(name: name)
DispatchQueue.main.async {
self.image = image
}
}
}
}