🎆

【iOS】AVFoundationを使用してRAWデータ撮影機能を実装する

に公開

AVFoundationのCapture APIを使用して、RAWデータ撮影機能を実装する方法について書きます。以下の記事を先にお読みいただくと、本記事の内容をスムーズに理解することができます。
https://zenn.dev/naoya_maeda/articles/6f5c6bec557393

本記事をお読みいただくことで、以下の内容を学ぶことができます。

  • RAWデータを出力するキャプチャセッションの設定方法
  • RAWデータに対応するピクセルフォーマットを取得する方法
  • RAWデータの撮影を開始する方法
  • デリゲートメソッドを介したRAWデータの取得方法
  • RAWデータを一つのアセットで写真アルバムに追加する方法

本記事の内容は、「詳解 AVFoundation Capture」から一部の説明を抜粋した内容になっています。
https://naoya-maeda.booth.pm/items/6760109
アプリがカメラやマイク、写真アルバムへアクセスするために必要なアクセス権を取得する方法については、本記事では割愛しています。「詳解 AVFoundation Capture」の「第2章 アクセス権」または、以下のドキュメントをご参照ください。
https://developer.apple.com/documentation/avfoundation/requesting-authorization-to-capture-and-save-media

キャプチャセッションの設定

RAWデータ撮影を行うためのキャプチャセッション設定は、静止画データ撮影を行う時と同じです。AVCapturePhotoOutput オブジェクトをAVCaptureSession オブジェクトに追加することで、AVCapturePhotoCaptureDelegate プロトコルで定義されているデリゲートメソッドを介して、撮影したRAWデータを取得することができます。RAWデータを撮影する時は、AVCaptureSession オブジェクトのsessionPreset プロパティに、AVCaptureSession.Preset.photo オブジェクトを代入します。以下のソースコードでは、RAWデータ撮影を行うためのキャプチャセッションの設定を行なっています。

撮影オプション設定

AVCapturePhotoSettings は、静止画データを撮影する時の撮影オプション設定を行うことができるクラスです。
https://developer.apple.com/documentation/avfoundation/avcapturephotosettings

AVCapturePhotoSettings オブジェクトの各プロパティに、撮影オプション設定に対応するオブジェクトを代入することで、静止画データ撮影に関する設定を制御することができます。RAWデータ撮影を行うために、AVCapturePhotoSettingsinit(rawPixelFormatType:processedFormat:) イニシャライザで、RAW データ撮影を行うためのAVCapturePhotoSettings オブジェクトを取得します。
https://developer.apple.com/documentation/avfoundation/avcapturephotosettings/init(rawpixelformattype:processedformat:)

rawPixelFormatType 引数には、RAW データのピクセルフォーマットタイプを表すOSType オブジェクトを指定します。RAW データのピクセルフォーマットタイプ表すOSType オブジェクトは、AVCapturePhotoOutput オブジェクトのavailableRawPhotoPixelFormatTypes プロパティで取得することができます。
https://developer.apple.com/documentation/avfoundation/avcapturephotooutput/availablerawphotopixelformattypes-9t9k5

availableRawPhotoPixelFormatTypes は、RAW / Apple ProRAW といったRAWデータのピクセルフォーマットタイプを表すOSType オブジェクトの配列が代入されているプロパティです。以下のソースコードでは、RAW データのピクセルフォーマットタイプを表すOSType オブジェクトを取得しています。

isBayerRAWPixelFormat(_:) は、第一引数に指定したOSType オブジェクトが、RAW データのピクセルフォーマットタイプを表すOSType オブジェクトかどうかを表すBool 値を返すメソッドです。
https://developer.apple.com/documentation/avfoundation/avcapturephotooutput/isbayerrawpixelformat(_:)

query 変数には、引数に指定したOSType オブジェクトが、RAWデータのピクセルフォーマットタイプを表すOSType オブジェクトかどうかを判定するクロージャを代入しています。availableRawPhotoPixelFormatTypes.first(where: query) で、RAWデータのピクセルフォーマットタイプを表すOSType オブジェクトを取得しています。

以下のソースコードでは、RAWデータ撮影を行うためのAVCapturePhotoSettings オブジェクトを取得しています。

静止画データ・RAW データ撮影の開始

AVCapturePhotoOutput オブジェクトのcapturePhoto(with:delegate:) メソッドで、RAWデータ撮影を開始することができます。
https://developer.apple.com/documentation/avfoundation/avcapturephotooutput/capturephoto(with:delegate:)

with 引数には、先ほど取得したRAWデータ撮影を行うためのAVCapturePhotoSettings オブジェクトを指定します。delegate 引数には、AVCapturePhotoCaptureDelegate プロトコルに準拠するオブジェクトを指定します。AVCapturePhotoCaptureDelegate プロトコルで定義されているデリゲートメソッドについては後述しますが、上記のソースコードでは、self を指定しています。AVCapturePhotoCaptureDelegate プロトコルに準拠したオブジェクトに、RAW データ撮影の開始から完了するまでに呼び出されるデリゲートメソッドを定義します。

プロトコルへの準拠

capturePhoto(with:delegate:) メソッドのdelegate 引数に、RAWデータ撮影の開始から完了するまでに呼び出されるデリゲートメソッドの委譲先を指定しました。今回は、移譲先にself を指定したので、capturePhoto(with:delegate:) メソッドを実行するクラス自身にデリゲートメソッドを定義します。デリゲートメソッドを定義するために、selfAVCapturePhotoCaptureDelegate プロトコルに準拠させます。

RAW データ・静止画データの取得

photoOutput(_:didFinishProcessingPhoto:error:) は、AVCapturePhotoCaptureDelegate プロトコルで定義されているデリゲートメソッドです。
https://developer.apple.com/documentation/avfoundation/avcapturephotocapturedelegate/photooutput(_:didfinishprocessingphoto:error:)

静止画データが出力される時に呼び出されます。RAWデータ撮影を行う時は、RAW データと圧縮済みデータの二つが出力されます。つまり、photoOutput(_:didFinishProcessingPhoto:error:) メソッドは、合計二回呼び出されます。出力された両データは、photo 引数に代入されているAVCapturePhoto オブジェクトで取得することができます。AVCapturePhoto は、静止画データやメタデータ情報を格納することができるクラスです。
https://developer.apple.com/documentation/avfoundation/avcapturephoto

RAWデータの取得処理を行う前に、AVCapturePhoto オブジェクトのisRawPhoto プロパティを確認します。
https://developer.apple.com/documentation/avfoundation/avcapturephoto

isRawPhoto は、自身に格納されているデータがRAWデータかどうかを表すBool 値が代入されているプロパティです。自身に代入されているデータがRAWデータの時、isRawPhoto プロパティにはtrue が代入されています。以下のソースコードでは、静止画データをcompressedData 変数に代入し、rawImageFileURL 変数に代入されているURL オブジェクトが表すドキュメントフォルダパスに、RAWデータを書き込んでいます。

取得した静止画データを表すData オブジェクトと、ドキュメントフォルダパスを表すURL オブジェクトは、別のデリゲートメソッド内で、静止画データとRAW データを写真アルバムへ追加する処理を行う時に使用するため、変数に保持しておきます。

「RAW + L」データを写真アルバムへ追加

photoOutput(_:didFinishProcessingPhoto:error:) は、AVCapturePhotoCaptureDelegate プロトコルで定義されているデリゲートメソッドです。
https://developer.apple.com/documentation/avfoundation/avcapturephotocapturedelegate/photooutput(_:didfinishcapturefor:error:)

撮影に関連する全ての処理が完了した時に呼び出されます。「RAW + L」データ(RAW データとLarge サイズの圧縮済みデータ) を写真アルバムへ追加する処理は、photoOutput(_:didFinishCaptureFor:error:) メソッド内で行います。「RAW + L」データ(以降、アセットデータ) を写真アルバムに追加する処理は、PhotoKitフレームワークのAPIを使用します。PhotoKitは、写真アルバムを操作するためのAPI が定義されているフレームワークです。写真アルバムに変更を加える時は、PHPhotoLibraryperformChanges(_:) メソッドを実行します。
https://developer.apple.com/documentation/photos/phphotolibrary/performchanges(_:completionhandler:)

performChanges(_:) は、第一引数に指定した写真アルバムに変更を加える処理を、PhotoKitにリクエストするメソッドです。

第一引数には、写真アルバムを操作する処理をクロージャで記述します。写真アルバムに対する変更は、PHAssetCreationRequest オブジェクトのメソッドで行います。PHAssetCreationRequest は、写真アルバムに対する変更をPhotoKitにリクエストすることができるメソッドを持つクラスです。
https://developer.apple.com/documentation/Photos/PHAssetCreationRequest

PHAssetCreationRequest オブジェクトは、forAsset() メソッドで取得することができます。
https://developer.apple.com/documentation/Photos/PHAssetCreationRequest

Data オブジェクトのアセットデータを写真アルバムに追加する時は、PHAssetCreationRequest オブジェクトのaddResource(with:data:options:) メソッドを実行します。
https://developer.apple.com/documentation/photos/phassetcreationrequest/addresource(with:data:options:)

addResource(with:data:options:) は、data 引数に指定したData オブジェクトのアセットデータを、写真アルバムに追加することをPhotoKitにリクエストするメソッドです。with 引数には、写真アルバムに追加するアセットのタイプを、PHAssetResourceType オブジェクトで指定します。今回は、静止画データを写真アルバムに追加するので、上記のソースコードでは、with 引数に.photo を指定しています。data 引数には、写真アルバムに追加するアセットデータを、Data オブジェクトで指定します。上記のソースコードでは、撮影した圧縮済み静止画データが代入されているcompressedData 変数を指定しています。

次に、RAWデータを写真アルバムに追加することをリクエストするメソッドを実行します。特定のドキュメントフォルダパスに書き込まれているアセットデータを写真アルバムに追加する時は、PHAssetCreationRequest オブジェクトのaddResource(with:fileURL:options:) メソッドを実行します。
https://developer.apple.com/documentation/photos/phassetcreationrequest/addresource(with:fileurl:options:)

静止画データにRAW データを関連づけて、「RAW + L」データとして写真アルバムに追加する時は、with 引数に.alternatePhoto を指定します。.alternatePhoto を指定することで、事前に実行したaddResource(with:data:options:) メソッドで、写真アルバムに追加することをリクエストした静止画データに対してRAW データを関連づけることが、PhotoKitにリクエストされます。

options 引数には、PHAssetResourceCreationOptions オブジェクトを指定します。PHAssetResourceCreationOptions は、アセットデータを写真アルバムに追加する時の追加処理オプションを設定することができるクラスです。
https://developer.apple.com/documentation/photos/phassetresourcecreationoptions

ドキュメントフォルダパスに配置されているRAWデータを写真アルバムに追加した後に、元のRAWデータが不要な時は、PHAssetResourceCreationOptions オブジェクトのshouldMoveFile プロパティにtrue を代入します。shouldMoveFile プロパティにtrue を代入したPHAssetResourceCreationOptions オブジェクトをoptions 引数に指定することで、元のRAWデータが写真アルバムに移動してから、RAWデータを写真アルバムに追加する処理が行われます。つまり、元のRAWデータが配置されていたドキュメントフォルダパスにはRAWデータが存在しなくなり、端末のストレージを節約することができます。

以下のソースコードでは、photoOutput(_:didFinishCaptureFor:error:) メソッド内で静止画データにRAWデータを関連づけて、「RAW + L」データを一つのアセットデータとして、写真アルバムに追加する処理を行っています。

参考資料

・詳解 AVFoundation Capture
https://naoya-maeda.booth.pm/items/6760109

・Capturing Photos in RAW and Apple ProRAW Formats
https://developer.apple.com/documentation/avfoundation/capturing-photos-in-raw-and-apple-proraw-formats

Discussion