Live Photo開發,瞭解之後可以將其應用於開發過程中。 ...
前言
Apple從iPhone6s開始支持Live Photo。Live Photo 會錄下拍照前後 1.5 秒所發生的一切,因此用戶獲得的不僅僅是一張精美照片,還有拍照前後時刻的動作和聲音。具體的操作可以參見拍照和編輯。
本文接下來要介紹的是如何在項目開發過程中使用Live Photo以及相容其他平臺使用Live Photo。這些平臺包括iOS、Web和Android。接下來就開始進行介紹。
正文
先瞭解幾個概念。
HEVC:全稱High Efficiency Video Coding。它是一種高效的視頻編碼,是符合行業標準的下一代視頻編碼技術,繼承自H.264編碼。Apple想要添加新的功能特性,但是當前的H.264已經無法滿足Apple的需求,因此HEVC應運而生。
HEIF:全稱High Efficiency Image File(Format),是一種高效率的圖片文件格式,是中靜止圖像和圖像序列的現代容器格式。
蘋果從iOS11開始已經預設啟動了HEVC電影和HEIF圖像存儲。也就是說iOS11以及以後版本的手機拍攝的圖片預設存儲的格式都是HEIF。但是我們可以嘗試將手機拍攝的圖片發送給其他人,你會發現圖片的格式依然是JPG。這是Apple做了相容,讓拍攝的照片更好地跨平臺支持。但是如果你用Mac上的Photo(應用)將Live Photo以原圖的形式導出,你會發現它導出的內容不再是JPG格式的文件,而是一個HEIC文件+一個mov文件。
Apple其實是通過圖片+視頻的方式實現了Live Photo。
先簡單介紹多平臺展示Live Photo的思路:
蘋果手機用戶將Live Photo上傳到伺服器,此時上傳的是一張圖片+視頻。當展示的時候分以下幾種情況:
- 對於蘋果手機的用戶,可以從服務端獲取圖片+視頻,然後將其合成Live Photo進行展示
- 對於Android手機用戶,可以模擬Live Photo,將圖片覆蓋到視頻上,然後進行隱藏展示播放。當播放時隱藏圖片,讓視頻播放;當停止播放時顯示圖片覆蓋視頻,停止視頻播放
- 對於Web用戶,可以直接使用Apple官方提供的LivePhotosKit JS,按照其使用方法將圖片和視頻載入到DOM元素中展示。Apple也提供了官方的一個Web展示Live Photo的Demo,點擊這裡查看。
接下來分平臺進行操作處理。
iOS
首先,我們如果想要手動獲取Live Photo的源文件,蘋果推薦了下麵幾種方式:
1.Using macOS Image Capture
- Connect your iOS device to your Mac.(使用數據線將設備連接到你的Mac)
- Select the Live Photo you wish to import from your device to your local file system.(選擇你想要導出到你本地文件系統的Live Photo)
- Choose the destination folder and click on Import.(選擇你的目標文件夾,然後點擊導入)
2.Using macOS Photos
- Connect your iOS device to your Mac.(將你的iOS設備和Mac相連)
- Import your photos into the Photos application.(把你手機上的圖片導入到Photos應用程式中)
- Select the Live Photo you wish to export.(選中你想要導入的Live Photo)
- Use File > Export > Export Unmodified Original to export to your file system.(導出,選擇導出一張未修改的原件即可)
3.Using Windows 10 File Explorer
- Ensure that iTunes for Windows is installed. You can download it from here: http://www.apple.com/itunes/download/
- Open File Explorer. This can be opened by pressing the Windows Key and E at the same time.
- Connect your iOS device to your PC.
- You should see your iOS device in the "This PC" folder.
- Navigate to the following folder: (your device) > Internal Storage > DCIM and look for the Live Photo you wish to import.
- Your Live Photo will be stored as a pair of files: a JPG file and a MOV file.
- Drag the pair of files to your local file system.
導出之後,得到了兩個文件:一個是尾碼為HEIC的圖像文件,一個是mov尾碼的視頻文件。此時,便可以手動將圖片+視頻上傳到Server,然後供其他端使用。
如果是用戶使用自己的iOS設備上傳圖片,我們可以先通過PHAssetCollection或者PHAsset獲取圖片,這裡有個demo:我通過PHAsset.fetchAssets(with:photoOptions)可以獲取手機上面所有的圖片。還有一個PHAssetCollection的類,它代表圖庫中的組,例如時刻、用戶創建的相冊或者是smart album。我們可以使用該類獲取所有的smartAlbum集合:
var smartAlbums: PHFetchResult<PHAssetCollection>! //smart albums
smartAlbums = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: .albumRegular, options: nil)
這裡的.smartAlbum就是圖庫中的組的集合,是一個枚舉:
public enum PHAssetCollectionType : Int {
case album
case smartAlbum
case moment
}
此時拿到的smartAlbums就是一組group,每個group中又包含了符合該組條件的圖片例如:
左邊Smart Albums是獲取到的smartAlbums,裡面對圖片做了智能分類,包括最近刪除的、屏幕快照、Live Photos、Videos等等。右邊是點擊Live Photos進入的頁面。裡面全部是Live Photo。圖片縮略圖頁面的數據是通過上一個頁面傳入的group中單個collection:
imgListVC.photosList = PHAsset.fetchAssets(in: smartAlbums.object(at: indexPath.row), options: nil)
這裡的PHAsset.fetchAssets是從某個PHAssetCollection中獲取該Collection中的所有圖片集合,返回結果:
var photosList: PHFetchResult<PHAsset>? = nil
也就是PHFetchResult類型,是一個結果集。拿到結果集之後,便可以在圖片列表頁面展示:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let collectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: CellIdentifier, for: indexPath) as! ImageCollectionCell
let asset = photosList?.object(at: indexPath.row)
if (asset?.mediaSubtypes.contains(.photoLive))! {
collectionViewCell.badgeImage = PHLivePhotoView.livePhotoBadgeImage(options: .overContent)
}
imageManager.requestImage(for: asset!, targetSize: CGSize.init(width: 80, height: 80), contentMode: .aspectFill, options: nil, resultHandler: { image, _ in
// The cell may have been recycled by the time this handler gets called;
// set the cell's thumbnail image only if it's still showing the same asset.
collectionViewCell.smallImage = image
})
return collectionViewCell
}
這裡使用的UICollectionView充當容器。collectionViewCell.badgeImage(自定義的image,用於展示左上角的live photo標識)的獲取方式很獨特,是PhotosUI中自帶的API獲取的:
PHLivePhotoView.livePhotoBadgeImage(options: .overContent)
PHLivePhotoView是繼承與UIview的一個子類,可以把它理解為UIImageView,只不過UIImageView是用於展示靜態圖片,而PHLivePhotoView用於展示Live Photo。該類有一個livePhotoBadgeImage的方法用於獲取live photo的標識圖片,選項.overContent是Live Photo正常展示的角標,而.liveOff則是在角標上添加了斜杠,可自行嘗試。
接下來就是獲取要展示的圖片,這裡使用到了PHCachingImageManager類,該類主要是提供用於檢索或者生成預覽圖像。所以展示的預覽圖就是通過該類生成的。調用它的requestImage方法,將asset傳入,便可獲UIImage對象。
當點擊某個圖片進去詳情頁面時,通過傳入的asset便可獲取Live Photo,併在PHLivePhotoView上展示:
PHImageManager.default().requestLivePhoto(for: asset, targetSize: view.frame.size, contentMode: .aspectFit, options: options) { (livePhoto, info) in
guard livePhoto != nil else {return}
self.livePhotoImageView.livePhoto = livePhoto
}
這裡使用的是PHImageManager,可以通過該類獲取 PHLivePhoto對象。
寫了這麼多,只是從相冊中獲取了Live Photo,然後將其展示。那如何獲取該Live Photo的源文件呢?很簡單,直接看下麵代碼:
@objc func getSourceAction() {
let arr = PHAssetResource.assetResources(for: asset)
let manager = PHAssetResourceManager.default()
let resourceReqOptions = PHAssetResourceRequestOptions.init()
manager.requestData(for: arr[0], options: resourceReqOptions, dataReceivedHandler: { (data) in
let image = UIImage.init(data: data, scale: 1)
print(image ?? "沒有圖片")
}) { (error) in
print(error?.localizedDescription ?? "err")
}
print(arr)
}
這是點擊獲取資源觸發的Action操作,主要用到了PHAssetResource和PHAssetResourceManager。
PHAssetResource是於照片庫中的圖片視頻或者Live Photo 相關連的底層數據資源,也就是說我可以通過此類獲取Live Photo的圖片+視頻:
通過PHAsset獲取asset 資源數組,對Live Photo而言,數組包含了圖片+視頻。這樣如果用戶是通過iOS設備上傳Live Photo,開發者可以獲取到視頻和圖片分別上傳。然後其他端通過使用圖片+視頻模擬Live Photo的展示。
還有一個問題,如果是iOS設備上,如何將網路獲取的圖片+視頻展示位Live Photo呢?
既然Apple提供了API讓開發者獲取Live Photo的原始資源,也可以通過原始資源合成Live Photo:
open class func request(withResourceFileURLs fileURLs: [URL], placeholderImage image: UIImage?, targetSize: CGSize, contentMode: PHImageContentMode, resultHandler: @escaping (PHLivePhoto?, [AnyHashable : Any]) -> Swift.Void) -> PHLivePhotoRequestID
此方法是PHLivePhoto的類方法,作用是根據提供的資源文件非同步合成Live Photo。這個方法中的URL為一個數組,內容為使用Photos庫導出的Live Photo的源文件(HEIC+mov)。
將生成的Live Photo保存到本地
直接看代碼:
PHPhotoLibrary.shared().performChanges({
let request = PHAssetCreationRequest.forAsset()
let options = PHAssetResourceCreationOptions.init()
let imageUrl = Bundle.main.path(forResource: "livephoto1", ofType: "HEIC")!
let vidoUrl = Bundle.main.path(forResource: "livephoto1", ofType: "mov")!
request.addResource(with: .pairedVideo, fileURL: URL.init(fileURLWithPath: vidoUrl), options: options)
request.addResource(with: .photo, fileURL: URL.init(fileURLWithPath: imageUrl), options: options)
}) { (boo, error) in
if boo {
print("保存到手機成功")
}else {
print(error?.localizedDescription ?? "error")
}
}
這裡主要使用的是PHAssetCreationRequest類。這裡要註意一點,那就是LivePhoto的視頻添加時, PHAssetResourceType為pairedVideo,這種類型是提供Live Photo原始視頻數據的格式。通過add操作之後,可以將合成的Live Photo保存到手機中。
按照上述的方式,便可以在iOS平臺上面去使用Live Photo。
Android
Android本身不支持Live Photo,但是可以進行模擬。先從服務端拉取要展示的圖片+視頻,展示時,直接將圖片覆蓋到視頻上,當進行按壓時,隱藏圖片,播放視頻即可。
Web
Apple為了做線上播放Live Photo,官方開發了一套LivePhotoKit的js,通過該JS,開發者可以很容易地將圖片+視頻合稱為Live Photo展示到網頁中。這裡是Apple官方提供的Demo。自己有按照LivePhotoKit的指南去開發,但是發現相容性並不是很好,在Safari中展示沒有什麼問題,但是在Chrome和Firefox上展示提示播放失敗。這裡後續有待進一步研究。另外,在Web展示的時候如果你使用的外鏈圖片和視頻,容易產生跨域問題:
No 'Access-Control-Allow-Origin' header
所以最好通過自己在本地起一個服務,然後同源進行操作。具體的LivePhotoKit使用可以直接查看官方網站的使用。
結束
LivePhoto本質上就是圖片+視頻生成的一種新的照片格式。在對其進行操作的過程中主要用到的Photos+PhotosUI。
代碼Demo可參見這裡。
如有什麼疑問,可留言咨詢!
參考鏈接
1.LivePhotosKit JS
2.Example app using Photos framework
3.Live Photo Editing and RAW Processing with Core Image
4.Working with HEIF and HEVC
5.PHAssetResourceManager usage?
6.拍攝和編輯livephoto
7.FLLivePhotoDemo
8.Live Photo存儲與應用
9.iOS開發創建合成一張LivePhoto