// // Gif.swift // SwiftGif // // Created by Arne Bahlo on 07.06.14. // Copyright (c) 2014 Arne Bahlo. All rights reserved. // import UIKit import ImageIO // MARK: - REFACTOR extension UIImageView { public func loadGif(name: String) { DispatchQueue.global().async { let image = UIImage.gif(name: name) DispatchQueue.main.async { self.image = image } } } public func loadGif(asset: String) { DispatchQueue.global().async { let image = UIImage.gif(asset: asset) DispatchQueue.main.async { self.image = image } } } } extension UIImage { public class func gif(data: Data) -> UIImage? { guard let source = CGImageSourceCreateWithData(data as CFData, nil) else { return nil } return .animatedImageWithSource(source) } public class func gif(url: String) -> UIImage? { guard let bundleURL = URL(string: url) else { return nil } guard let imageData = try? Data(contentsOf: bundleURL) else { return nil } return gif(data: imageData) } public class func gif(name: String) -> UIImage? { guard let bundleURL = Bundle.main.url(forResource: name, withExtension: "gif") else { return nil } guard let imageData = try? Data(contentsOf: bundleURL) else { return nil } return gif(data: imageData) } public class func gif(asset: String) -> UIImage? { guard let dataAsset = NSDataAsset(name: asset) else { return nil } return gif(data: dataAsset.data) } internal class func delayForImageAtIndex(_ index: Int, source: CGImageSource!) -> Double { var delay = 0.1 let cfProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil) let gifPropertiesPointer = UnsafeMutablePointer.allocate(capacity: 0) defer { gifPropertiesPointer.deallocate() } let unsafePointer = Unmanaged.passUnretained(kCGImagePropertyGIFDictionary).toOpaque() if CFDictionaryGetValueIfPresent(cfProperties, unsafePointer, gifPropertiesPointer) == false { return delay } let gifProperties: CFDictionary = unsafeBitCast(gifPropertiesPointer.pointee, to: CFDictionary.self) var delayObject: AnyObject = 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 ) } if let delayObject = delayObject as? Double, delayObject > 0 { delay = delayObject } else { delay = 0.1 } return delay } internal class func gcdForPair(_ lhs: Int?, _ rhs: Int?) -> Int { guard var rhs, var lhs else { if let rhs { return rhs } else if let lhs { return lhs } return 0 } if lhs < rhs { let ctp = lhs lhs = rhs rhs = ctp } var rest: Int while true { rest = lhs % rhs if rest == 0 { return rhs } else { lhs = rhs rhs = rest } } } internal class func gcdForArray(_ array: [Int]) -> Int { if array.isEmpty { return 1 } var gcd = array[0] for val in array { gcd = UIImage.gcdForPair(val, gcd) } return gcd } internal class func animatedImageWithSource(_ source: CGImageSource) -> UIImage? { let count = CGImageSourceGetCount(source) var images = [CGImage]() var delays = [Int]() for index in 0..