如何把 GIF 動圖保存到相冊?
iOS 的相冊是支持保存 GIF 和 APNG 動圖的,只是不能直接播放。用 [ALAssetsLibrary writeImageDataToSavedPhotosAlbum:metadata:completionBlock] 可以直接把 APNG、GIF 的數據寫入相冊。如果圖省事直接用 UIImageWriteToSavedPhotosAlbum() 寫相冊,那麼圖像會被強制轉碼為 PNG。
將 UIImage 保存到磁盤,用什麼方式最好?
目前來說,保存 UIImage 有三種方式:1.直接用 NSKeyedArchiver 把 UIImage 序列化保存,2.用 UIImagePNGRepresentation() 先把圖片轉為 PNG 保存,3.用 UIImageJPEGRepresentation() 把圖片壓縮成 JPEG 保存。
實際上,NSKeyedArchiver 是調用了 UIImagePNGRepresentation 進行序列化的,用它來保存圖片是消耗最大的。蘋果對 JPEG 有硬編碼和硬解碼,保存成 JPEG 會大大縮減編碼解碼時間,也能減小文件體積。所以如果圖片不包含透明像素時,UIImageJPEGRepresentation(0.9) 是最佳的圖片保存方式,其次是 UIImagePNGRepresentation()。
UIImage 緩存是怎麼回事?
通過 imageNamed 創建 UIImage 時,系統實際上只是在 Bundle 內查找到文件名,然後把這個文件名放到 UIImage 裡返回,並沒有進行實際的文件讀取和解碼。當 UIImage 第一次顯示到屏幕上時,其內部的解碼方法才會被調用,同時解碼結果會保存到一個全局緩存去。據我觀察,在圖片解碼後,App 第一次退到後台和收到內存警告時,該圖片的緩存才會被清空,其他情況下緩存會一直存在。
我要是用 imageWithData 能不能避免緩存呢?
不能。通過數據創建 UIImage 時,UIImage 底層是調用 ImageIO 的 CGImageSourceCreateWithData() 方法。該方法有個參數叫 ShouldCache,在 64 位的設備上,這個參數是默認開啟的。這個圖片也是同樣在第一次顯示到屏幕時才會被解碼,隨後解碼數據被緩存到 CGImage 內部。與 imageNamed 創建的圖片不同,如果這個圖片被釋放掉,其內部的解碼數據也會被立刻釋放。
怎麼能避免緩存呢?
1. 手動調用 CGImageSourceCreateWithData() 來創建圖片,並把 ShouldCache 和 ShouldCacheImmediately 關掉。這麼做會導致每次圖片顯示到屏幕時,解碼方法都會被調用,造成很大的 CPU 占用。
2. 把圖片用 CGContextDrawImage() 繪制到畫布上,然後把畫布的數據取出來當作圖片。這也是常見的網絡圖片庫的做法。
我能直接取到圖片解碼後的數據,而不是通過畫布取到嗎?
1.CGImageSourceCreateWithData(data) 創建 ImageSource。
2.CGImageSourceCreateImageAtIndex(source) 創建一個未解碼的 CGImage。
3.CGImageGetDataProvider(image) 獲取這個圖片的數據源。
4.CGDataProviderCopyData(provider) 從數據源獲取直接解碼的數據。
ImageIO 解碼發生在最後一步,這樣獲得的數據是沒有經過顏色類型轉換的原生數據(比如灰度圖像)。
如何判斷一個文件的圖片類型?
通過讀取文件或數據的頭幾個字節然後和對應圖片格式標准進行比對。我在這裡寫了一個簡單的函數,能很快速的判斷圖片格式。
怎樣像浏覽器那樣邊下載邊顯示圖片?
首先,圖片本身有 3 種常見的編碼方式:
第一種是 baseline,即逐行掃描。默認情況下,JPEG、PNG、GIF 都是這種保存方式。
第二種是 interlaced,即隔行掃描。PNG 和 GIF 在保存時可以選擇這種格式。
第三種是 progressive,即漸進式。JPEG 在保存時可以選擇這種方式。
在下載圖片時,首先用 CGImageSourceCreateIncremental(NULL) 創建一個空的圖片源,隨後在獲得新數據時調用
CGImageSourceUpdateData(data, false) 來更新圖片源,最後在用 CGImageSourceCreateImageAtIndex() 創建圖片來顯示。
你可以用 PINRemoteImage 或者我寫的 YYWebImage 來實現這個效果。SDWebImage 並沒有用 Incremental 方式解碼,所以顯示效果很差。