この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
こんにちは。モバイルアプリサービス部の平屋です。
iOS 10 で「Live Photos」を編集することができるようになりました。本記事では、Photos framework のクラスを使用して Live Photos を編集する手順を紹介していきます。
今回解説するコードは以下のリポジトリで公開してますのであわせてご覧ください。
Live Photos とは
Live Photos は iPhone 6s / 6s Plus 以降の機種で、標準の「カメラ」アプリで撮影できます。
撮影するときの操作は静止画を撮影する場合と同様ですが、静止画だけでなく「写真を撮影したタイミングの前後1.5秒の映像・音声」も記録されます。
実装
さっそく、Live Photos を編集する手順を紹介していきます。
Live Photos を編集するために、Photos framework の機能を使用します。Photos framework の基本事項については以下のカテゴリの記事をご覧ください。
また、Live Photos を編集する手順は、静止画を編集する場合とほとんど同じです。静止画を編集する手順は以下の記事で解説しています。
func applyFilter() {
guard let asset = self.asset else { return }
let formatIdentifier = Bundle.main.bundleIdentifier!
let formatVersion = "1.0"
let filterName = "CISepiaTone"
// [1] PHContentEditingInputRequestOptions を作成する
let options = PHContentEditingInputRequestOptions()
options.canHandleAdjustmentData = { adjustmentData in
return adjustmentData.formatIdentifier == formatIdentifier && adjustmentData.formatVersion == formatVersion
}
// [2] コンテンツの編集がサポートされているかを問い合わせる
if !asset.canPerform(.content) { return }
// [3] コンテンツ編集セッションを開始するために必要な情報をリクエストする
asset.requestContentEditingInput(with: options, completionHandler: { input, info in
guard let input = input else { fatalError("can't get content editing input: \(info)") }
// [4] PHAdjustmentData を作成する
let adjustmentData = PHAdjustmentData(formatIdentifier: formatIdentifier,
formatVersion: formatVersion,
data: filterName.data(using: .utf8)!)
// [5] PHContentEditingOutput を作成する
let output = PHContentEditingOutput(contentEditingInput: input)
output.adjustmentData = adjustmentData
// [6] PHLivePhotoEditingContext を作成する
guard let livePhotoContext = PHLivePhotoEditingContext(livePhotoEditingInput: input) else { fatalError("can't get live photo to edit") }
// [7] PHLivePhotoEditingContext に編集処理を行うブロックをセットする
livePhotoContext.frameProcessor = { frame, _ in
return frame.image.applyingFilter(filterName, withInputParameters: nil)
}
// [8] 編集処理を実行し、レンダリング結果を PHContentEditingOutput に渡す
livePhotoContext.saveLivePhoto(to: output) { success, error in
if success {
// [9] 編集結果をフォトライブラリにコミットする
PHPhotoLibrary.shared().performChanges({
let request = PHAssetChangeRequest(for: asset)
request.contentEditingOutput = output
}, completionHandler: { success, error in
if !success {
print(Date(), #function, #line, "cannot edit asset: \(error)")
}
})
} else {
print(Date(), #function, #line, "cannot output live photo")
}
}
})
}
[1] PHContentEditingInputRequestOptions を作成する
手順 [3] で使用する PHContentEditingInputRequestOptions
をここで作成します。
canHandleAdjustmentData
プロパティにセットするブロック内で true
を返した場合、編集用のオリジナルデータが提供されます。false
を返した場合は、以前行なった編集がレンダリングされたデータが提供されます。
ブロック内では PHAdjustmentData
が保持する formatIdentifier
と formatVersion
をチェックした結果を返しています。PHAdjustmentData
は Asset に対する編集履歴を保持するクラスです。
[2] コンテンツの編集がサポートされているかを問い合わせる
PHAsset
の canPerform(_:)
メソッドを使用して編集処理がサポートされているかをチェックします。
[3] コンテンツ編集セッションを開始するために必要な情報をリクエストする
PHAsset
の requestContentEditingInput(with:completionHandler:)
メソッドを使用して PHAsset
の編集セッションを開始するために必要な PHContentEditingInput
をリクエストします。
1 つ目の引数には、手順 [1] で作成した PHContentEditingInputRequestOptions
を渡します。completionHandler
引数に渡すブロックは、PHContentEditingInput
が用意出来たタイミングで呼ばれます。
[4] PHAdjustmentData を作成する
formatIdentifier
, formatVersion
, data
から、PHAdjustmentData
を作成します。data
にはフィルタ名を指定しています。
[5] PHContentEditingOutput を作成する
PHAsset
のコンテンツの編集結果を表すオブジェクトである PHContentEditingOutput
を作成し、手順 [4] で作成した PHAdjustmentData
をセットします。
[6] PHLivePhotoEditingContext を作成する
PHContentEditingInput
から PHLivePhotoEditingContext
を作成します。PHLivePhotoEditingContext
は Live Photos のコンテンツ編集セッションを管理するクラスです。
[7] PHLivePhotoEditingContext に編集処理を行うブロックをセットする
PHLivePhotoEditingContext
の frameProcessor
プロパティに編集処理を行うブロックをセットします。
ブロック内の処理は Live Photos の各フレームに対して実行されます。今回は CIImage
の applyingFilter(_:withInputParameters:)
メソッドを使用して画像を加工しました。
上記実装例では CISepiaTone
という Core Image API のフィルタを使用しています。Core Image API が提供するフィルタは以下のページに載っています。
[8] 編集処理を実行し、レンダリング結果を PHContentEditingOutput に渡す
PHLivePhotoEditingContext
の saveLivePhoto(to:options:completionHandler:)
メソッドを呼びます。手順 [7] でセットした編集処理が実行され、手順[5] で作成したPHContentEditingOutput
にレンダリング結果が渡されます。
[9] 編集結果をフォトライブラリにコミットする
最後に、PHPhotoLibrary
の performChanges(_:completionHandler:)
メソッドを使用して、編集結果をフォトライブラリにコミットします。
1 つ目のブロック内に編集処理を記述します。PHAssetChangeRequest
を作成し、contentEditingOutput
プロパティに手順[5] で作成したPHContentEditingOutput
をセットします。
2 つめのブロックに処理完了時の処理を記述します。
編集結果
3 種類のフィルタを使用して、Live Photos の編集を試してみました。
オリジナル
CIPhotoEffectInstant
CISepiaTone
CIPhotoEffectNoir
さいごに
Photos framework のクラスを使用して Live Photos を編集する手順を紹介しました。編集を完了させるまでの手順は多いですが、比較的簡単にコンテンツを編集することができます。
今回解説したコードは以下のリポジトリで公開してますので参考にしてみてください。
参考資料
WWDC documents
- Live Photo Editing and RAW Processing with Core Image - WWDC 2016 - Videos - Apple Developer
- Advances in iOS Photography - WWDC 2016 - Videos - Apple Developer
- Example app using Photos framework
- Sample Photo Editing Extension