【iOS】AVFoundationを使用して写真撮影アプリを開発する
AVFoundationを使用して写真撮影アプリを開発する方法について書きます。写真撮影機能だけならば書くべきコードは至ってシンプルです。本記事のサンプルコードは以下に置いています。
アクセス権限の確認
アプリからカメラやマイクといったiPhoneのデバイス、フォトライブラリや連絡先といったユーザデータへアクセスする時は、Info.plistにアクセスを行う項目とその理由を記載し、コード側でアクセス権限要求アラートを表示する処理を記述します。
Info.plistへの記載
Info.plistにアクセスを行う項目とその理由を記載します。写真撮影機能はiPhoneのカメラで撮影した写真をフォトライブラリに保存する為、必要なアクセス項目はカメラへのアクセス権限とフォトライブラリへのアクセス権限です。
アクセス権限項目 | Info.plistに記載する項目 |
---|---|
カメラ | Privacy - Camera Usage Description |
フォトライブラリ | Privacy - Photo Library Usage Description |
アクセス権限要求アラートの表示
カメラへのアクセス権限
現在のカメラへのアクセス権限状態は以下のメソッドで確認することができます。
func authorizationStatus(for: AVMediaType) -> AVAuthorizationStatus
for
に確認するアクセス権限のタイプを指定します。.video
を指定するとカメラへのアクセス権限状態を確認することができます。
カメラへのアクセス権限要求アラートは以下のメソッドで表示することができます。
func requestAccess(for mediaType: AVMediaType, completionHandler handler: @escaping (Bool) -> Void)
for
に要求するアクセス権限のタイプを指定します。.video
を指定するとカメラへのアクセス権限要求アラートを表示することができます。handler
にはアクセス権限確認後に行う処理を記述します。アクセスを許可した時はtrue
、許可しなかった時はfalse
が引数として渡ってくるので、結果に応じて処理を分岐させることができます。
以下のコードではカメラへのアクセス権限状態をswitch
文の引数として、状態が.notDetermined
つまり権限状態が未決定の時にアクセス権限要求アラートが表示されます。
フォトライブラリへのアクセス権限
現在のフォトライブラリへのアクセス権限状態は以下のメソッドで確認することができます。
func authorizationStatus(for: PHAccessLevel) -> PHAuthorizationStatus
for
には確認したいフォトライブラリへのアクセスレベルを指定します。フォトライブラリの写真やビデオを読み込んだり、フォトライブラリへ写真やビデオを保存する時は.readWrite
、フォトライブラリに写真やビデオを保存するだけなら.addOnly
を指定します。今回は撮影した写真を保存するだけなので.addOnly
を指定します。
フォトライブラリへのアクセス権限要求アラートは以下のメソッドで表示することができます。
func requestAuthorization(for: PHAccessLevel, handler: (PHAuthorizationStatus) -> Void)
こちらもfor
にはフォトライブラリへのアクセスレベルを指定します。今回は撮影した写真を保存するだけなので.addOnly
を指定します。handler
にはアクセス権限確認後に行う処理を記述します。
以下のコードではフォトライブラリへのアクセス権限状態をswitch
文の引数として、状態が.notDetermined
つまり権限状態が未決定の時にアクセス権限要求アラートが表示されます。
キャプチャセッションの構築
キャプチャセッションとは入力ソースと出力タイプを繋いでくれる中継局のような役割を果たしてくれるクラスです。カメラの映像をiPhoneの画面に表示して、写真を撮影するためにはキャプチャセッションを構築する必要があります。キャプチャセッションは sessions(セッション) に inputs(入力ソース) と outputs(出力タイプ) をセットすることで構築することができます。
キャプチャセッションを構築する手順は以下の6ステップです。
- iPhoneのカメラデバイス(
AVCaptureDevice
)を取得 -
AVCaptureDevice
を使用してAVCaptureDeviceInput
(入力ソース)を生成 -
AVCaptureSession
(セッション)にAVCaptureDeviceInput
(入力ソース)をセット -
AVCaptureSession
(セッション)にAVCapturePhotoOutput
(出力タイプ)をセット -
AVCaptureSession
のsessionPreset
に表示する映像の品質をセット -
AVCaptureSession
(セッション)からカメラ映像のプレビューレイヤー(AVCaptureVideoPreviewLayer
)を取得してカメラ映像を表示したいViewにセット
手順を詳しく解説していきます。
AVCaptureDevice
は入力デバイス(カメラ、マイク等)を抽象化したクラスです。AVCaptureDevice
を使用してAVCaptureDeviceInput
(入力ソース)を生成し、AVCaptureSession
(セッション)にセットします。
AVCapturePhotoOutput
は写真出力タイプを表すクラスです。AVCapturePhotoOutput
を生成し、AVCaptureSession
(セッション)にセットします。
sessionPreset
は撮影する写真の品質を指定するプロパティです。AVCaptureSession.Preset
型の要素をセットします。写真撮影を行う時はAVCaptureSession.Preset.photo
をセットします。
最後にAVCaptureSession
(セッション)カメラ映像のプレビューレイヤー(AVCaptureVideoPreviewLayer
)を取得して、カメラ映像を表示したいUIViewにセットします。これでキャプチャセッションの構築は完了です。
最後にAVCaptureSession
のstartRunning()
を実行するとカメラの映像データがキャプチャセッションに流れ始めます。
以下のコードではiPhoneの広角レンズバックカメラ(AVCaptureDevice
)を取得し、それを元に入力ソース(AVCaptureDeviceInput
)を生成しています。AVCaptureSession
に対してその生成した入力ソースをセット、出力タイプは写真出力(AVCapturePhotoOutput
)をセットし、カメラ映像のプレビューレイヤー(AVCaptureVideoPreviewLayer
)をpreviewImageView
にセットしています。映像の品質は標準のカメラアプリで写真を撮影する時と同じ品質にする為のプリセット(AVCaptureSession.Preset.photo
)をセットしています。
写真撮影の開始
AVCapturePhotoOutput
のcapturePhoto
を実行すると写真撮影が開始します。capturePhoto
の引数に写真撮影開始から完了するまでにコールされるデリゲートメソッドの委譲先と、撮影する写真のオプション情報を格納したAVCapturePhotoSettings
オブジェクトを指定します。移譲先はself
つまり以下のコードを記述したViewController
を指定しています。AVCapturePhotoSettings
オブジェクトに変更を加えることで写真を保存するフォーマットやメタデータを変更することができますが、写真を撮影するだけならば特に変更を加える必要はありません。
写真撮影で使用するデリゲートメソッド
写真撮影開始から終了までの間にいくつかのデリゲートメソッドがコールされますが、使用するデリゲートメソッドは以下の2つです。
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?)
func photoOutput(_ output: AVCapturePhotoOutput, didFinishCaptureFor resolvedSettings: AVCaptureResolvedPhotoSettings, error: Error?)
前項でデリゲートの移譲先をself
に指定しました。上記デリゲートメソッドをViewController
内に記述する為に、移譲先のViewController
はAVCapturePhotoCaptureDelegate
プロトコルに準拠する必要があります。
写真撮影のハンドリング処理
写真の出力完了
写真の出力が完了したタイミングでphotoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?)
がコールされます。引数のphoto
は撮影した写真データです。photo
の型はAVCapturePhoto
で、このままではフォトライブラリに保存することができません。そこでfileDataRepresentation()
を使用することでフォトライブラリに保存することができるData?
型に変換しています。写真を保存する時にこのData?
型のオブジェクトが必要になりますので変数で保持しておきます。
写真の保存
撮影に必要な一連の処理が全て完了したタイミングでphotoOutput(_ output: AVCapturePhotoOutput, didFinishCaptureFor resolvedSettings: AVCaptureResolvedPhotoSettings, error: Error?)
がコールされます。photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?)
内で保持しておいたData?
型のオブジェクトを写真データとして、PHPhotoLibrary.shared().performChanges
を使用してフォトライブラリに保存します。
以上で写真撮影機能の実装は完了です。次回はビデオ撮影機能について解説します。
Discussion