寫在前面的
一顆傷心死掉的橘子樹
不拘一世之利以為己私分足陨,
不以王天下為已處顯壤靶。
顯則明叉抡。萬物一府,死生同狀勤婚。
扯淡結束開始進入文章正題
iOS中GIF圖片是無法像jpg,png等一樣直接加載出來的涤伐,有很多的第三方庫也提供了這方面的功能馒胆,這里總結一下GIF圖片加載的幾種方式,以及使用多張png圖片合成GIF圖片的方法凝果。
加載GIF圖片
1.使用UIWebView/WKWebView
使用UIWebView/WKWebView相當于使用coreText 將GIF的數據編碼渲染到UIWebView/WKWebView上祝迂,使用data數據來加載,本地和網絡圖片差不多器净。
下面使用本地圖片來舉例
//1.使用webview來顯示GIF
self.view.addSubview(webview)
webview.frame = self.view.bounds
let path = Bundle.main.path(forResource: "timg", ofType: "gif")
if let data = try? Data.init(contentsOf: URL.init(fileURLWithPath: path!)) {
webview.load(data as Data, mimeType: "image/gif", characterEncodingName: "UTF-8", baseURL: Bundle.main.resourceURL!)
}
//當然也可以直接加載文件路徑,下面兩種load方法都可以實現(xiàn)
webview.load(URLRequest.init(url: URL.init(fileURLWithPath: path!)))
webview.loadFileURL(URL.init(fileURLWithPath: path!), allowingReadAccessTo: Bundle.main.resourceURL!)
//OC 的寫法類似型雳,就不重復寫了。
小結
我本地的原圖的寬度是500像素的山害,但是從上面的效果圖可以看到纠俭,圖片有并沒有按照像素來顯示,而是根據圖片比例來顯示浪慌,而且寬度自動為self.view的寬度冤荆。說明GIF圖片數據在渲染時并不能控制圖片顯示的大小,以及GIF執(zhí)行的幀數和運行次數权纤。
2.使用GIF 數據來實現(xiàn)
也可以使用 ImageIO 系統(tǒng)框架來實現(xiàn)GIF的播放钓简,很多第三方開源的庫也是這樣做的。類似SDWebImage汹想,Kingfisher外邓,以及YYImage 都可以實現(xiàn)一句話來加載GIF圖片的功能,其中Kingfisher 是swift語言古掏,另外兩個是OC的坐榆。
其實兩種語言都一樣,這邊只是介紹swift語言冗茸。
下面的方法是根據GIF的data數據來得到一個([UIImage], TimeInterval) 的元組
// MARK: - ImageIO
private func showGif() ->([UIImage], TimeInterval)? {
let path = Bundle.main.path(forResource: "timg", ofType: "gif")
let data = try? Data.init(contentsOf: URL.init(fileURLWithPath: path!))
let source = CGImageSourceCreateWithData(data as! CFData, nil)
let count = CGImageSourceGetCount(source!)
let options: NSDictionary = [kCGImageSourceShouldCache as String: true, kCGImageSourceTypeIdentifierHint as String: kUTTypeGIF]
var gifDuration = 0.0
var images = [UIImage]()
func frameDuration(from gifInfo: NSDictionary) -> Double {
let gifDefaultFrameDuration = 0.100
let unclampedDelayTime = gifInfo[kCGImagePropertyGIFUnclampedDelayTime as String] as? NSNumber
let delayTime = gifInfo[kCGImagePropertyGIFDelayTime as String] as? NSNumber
let duration = unclampedDelayTime ?? delayTime
guard let frameDuration = duration else { return gifDefaultFrameDuration }
return frameDuration.doubleValue > 0.011 ? frameDuration.doubleValue : gifDefaultFrameDuration
}
for i in 0 ..< count {
guard let imageRef = CGImageSourceCreateImageAtIndex(source!, i, options) else {
return nil
}
if count == 1 {
//只有一張圖片時
gifDuration = Double.infinity//無窮大
}else {
// Animated GIF
guard let properties = CGImageSourceCopyPropertiesAtIndex(source!, i, nil), let gifinfo = (properties as NSDictionary)[kCGImagePropertyGIFDictionary as String] as? NSDictionary else {
return nil
}
gifDuration += frameDuration(from: gifinfo)
}
images.append(UIImage.init(cgImage: imageRef, scale: UIScreen.main.scale, orientation: .up))
}
return (images, gifDuration)
}
然后在viewDidLoad 中調用下面的代碼
var imageView: UIImageView?
let (images, duration) = showGif()!
let animatedImage = UIImage.animatedImage(with: images, duration: duration)
imageView = UIImageView.init(image: animatedImage)
self.view.addSubview(imageView!)
imageView?.center = self.view.center
使用let animatedImage = UIImage.animatedImage(with: images, duration: duration)
可以創(chuàng)建一個動畫圖片席镀,然后使用imageView = UIImageView.init(image: animatedImage)
創(chuàng)建一個UIImageView? (為什么用這個方法呢匹中,因為這個不用寫imageView的width和height,會根據圖片的像素自動渲染大小豪诲,不用設置大小顶捷。。屎篱。)
小結
原圖的像素寬度為500服赎,模擬器的屏幕為@2x的像素,所以圖片顯示大小應該是剛剛好的交播。這種相對于webView來顯示就優(yōu)化得多重虑,也可以設置圖片動畫的持續(xù)時間。
同樣的道理秦士,我們如果用imags這個image數組 加入到ImageView動畫組中缺厉,就可以設置動畫的次數,就可以實現(xiàn)類似于新浪微博多個GIF圖的微博 GIF圖片會依次播放的功能隧土。
let (images, duration) = showGif()!
//let animatedImage = UIImage.animatedImage(with: images, duration: duration)
imageView = UIImageView.init(image: images.first)
self.view.addSubview(imageView!)
imageView?.center = self.view.center
imageView?.animationImages = images
imageView?.animationDuration = duration
imageView?.animationRepeatCount = 3
imageView?.startAnimating()
GIF圖片的顯示就介紹到這里
GIF的合成
GIF圖片合成思路:
多幀圖像合成GIF的過程和GIF分解多幀圖像的過程互逆提针,GIF圖片分解過程倒過來推,就是GIF圖像合成的過程曹傀。
從功能上來說辐脖,GIF圖片的合成分為以下三個主要部分。
(1)加載待處理的n張原始數據源皆愉。
(2)在Document目錄下構建GIF文件嗜价。
(3)設置GIF文件屬性,利用ImageIO編碼GIF文件幕庐。
1.首先將圖片加入到工程中
然后將讀取的圖片依次加載到images中久锥。
let bundlePath = Bundle.main.path(forResource: "images", ofType: "bundle")
print("bundlePath === \(bundlePath)")
var images = [UIImage]()
for i in 1 ..< 10 {
let path = bundlePath?.appending("/\(i).tiff")
let image = UIImage.init(contentsOfFile: path!)
images.append(image!)
}
2.構建在Document目錄下的GIF文件路徑。具體實現(xiàn)如下所示翔脱。
//構建在Document目錄下的GIF文件路徑
let docs = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentsDirectory = docs[0] as String
let gifPath = documentsDirectory+"/mine.gif"
print("gifPath === \(gifPath)")
let url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, gifPath as CFString, CFURLPathStyle.cfurlposixPathStyle, false)
let destion = CGImageDestinationCreateWithURL(url!, kUTTypeGIF, images.count, nil)
//CGImageDestinationCreateWithURL方法的作用是創(chuàng)建一個圖片的目標對象,為了便于大家理解媒鼓,這里把圖片目標對象比喻為一個集合體届吁。
//集合體中描述了構成當前圖片目標對象的一系列參數,如圖片的URL地址绿鸣、圖片類型疚沐、圖片幀數、配置參數等潮模。
//本代碼中將mine.gif的本地文件路徑作為參數1傳遞給這個圖片目標對象亮蛔,參數2描述了圖片的類型為GIF圖片,參數3表明當前GIF圖片構成的幀數擎厢,參數4暫時給它一個空值究流。
3.待處理圖片源已經加載到代碼中辣吃,GIF圖片Destination也已經完成構建,下面就需要使用ImageIO框架把多幀PNG圖片編碼到GIF圖片中芬探,其處理流程如下神得。
//設置gif圖片屬性,利用9張tiff圖片構建gif
let cgimagePropertiesDic = [kCGImagePropertyGIFDelayTime as String: 0.1]//設置每幀之間播放時間
let cgimagePropertiesDestDic = [kCGImagePropertyGIFDictionary as String: cgimagePropertiesDic]
for cgimage in images {
// 依次為gif圖像對象添加每一幀元素
CGImageDestinationAddImage(destion!, cgimage.cgImage!, cgimagePropertiesDestDic as CFDictionary?)
}
let gifPropertiesDic:NSMutableDictionary = NSMutableDictionary()
gifPropertiesDic.setValue(kCGImagePropertyColorModelRGB, forKey: kCGImagePropertyColorModel as String)
gifPropertiesDic.setValue(16, forKey:kCGImagePropertyDepth as String)// 設置圖像的顏色深度
gifPropertiesDic.setValue(3, forKey:kCGImagePropertyGIFLoopCount as String)// 設置Gif執(zhí)行次數, 0則為無限執(zhí)行
gifPropertiesDic.setValue(NSNumber.init(booleanLiteral: true), forKey: kCGImagePropertyGIFHasGlobalColorMap as String)
let gifDictionaryDestDic = [kCGImagePropertyGIFDictionary as String: gifPropertiesDic]
CGImageDestinationSetProperties(destion!, gifDictionaryDestDic as CFDictionary?)//為gif圖像設置屬性
CGImageDestinationFinalize(destion!)//最后釋放 目標對象 destion
//生成GIF圖片成功
這樣就生成GIF圖片成功了偷仿,最后我們來測試一下生成的GIF圖片能否成功顯示哩簿。
//測試一下顯示GIF圖片
let (images2, duration) = showGif(path: gifPath)!
let animatedImage = UIImage.animatedImage(with: images2, duration: duration)
imageView = UIImageView.init(image: animatedImage)
self.view.addSubview(imageView!)
imageView?.center = self.view.center
運行之后確實是可以顯示的
最后的話
最后附上demo 的地址
https://github.com/aichiko/Swift_Diary
喜歡的話可以點贊一下酝静。