iOS GIF圖片的加載和合成

寫在前面的

一顆傷心死掉的橘子樹

那顆死掉的橘子樹

不拘一世之利以為己私分足陨,
不以王天下為已處顯壤靶。
顯則明叉抡。萬物一府,死生同狀勤婚。

扯淡結束開始進入文章正題

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.首先將圖片加入到工程中


圖片導入到bundle中

然后將讀取的圖片依次加載到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
喜歡的話可以點贊一下酝静。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末节榜,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子别智,更是在濱河造成了極大的恐慌宗苍,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亿遂,死亡現(xiàn)場離奇詭異浓若,居然都是意外死亡,警方通過查閱死者的電腦和手機蛇数,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門挪钓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人耳舅,你說我怎么就攤上這事碌上。” “怎么了浦徊?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵馏予,是天一觀的道長。 經常有香客問我盔性,道長霞丧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任冕香,我火速辦了婚禮蛹尝,結果婚禮上,老公的妹妹穿的比我還像新娘悉尾。我一直安慰自己突那,他們只是感情好,可當我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布构眯。 她就那樣靜靜地躺著愕难,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上猫缭,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天葱弟,我揣著相機與錄音,去河邊找鬼饵骨。 笑死翘悉,一個胖子當著我的面吹牛,可吹牛的內容都是我干的居触。 我是一名探鬼主播妖混,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼轮洋!你這毒婦竟也來了制市?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤弊予,失蹤者是張志新(化名)和其女友劉穎祥楣,沒想到半個月后,有當地人在樹林里發(fā)現(xiàn)了一具尸體汉柒,經...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡误褪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了碾褂。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片兽间。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖正塌,靈堂內的尸體忽然破棺而出嘀略,到底是詐尸還是另有隱情,我是刑警寧澤乓诽,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布帜羊,位于F島的核電站,受9級特大地震影響鸠天,放射性物質發(fā)生泄漏讼育。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一稠集、第九天 我趴在偏房一處隱蔽的房頂上張望奶段。 院中可真熱鬧,春花似錦巍杈、人聲如沸忧饭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春鳖宾,著一層夾襖步出監(jiān)牢的瞬間吼砂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工鼎文, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留渔肩,地道東北人。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓拇惋,卻偏偏與公主長得像周偎,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子撑帖,可洞房花燭夜當晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內容