記録。

めも。

AVFoundationを使用して撮影した写真のExif情報を取得したり、追加してみる

昨日に引き続き、連投です。

今回はAVFoundationを使用したカメラで撮影した写真のExif情報を取得したり、追加したりする方法だったりを
書きたいと思います。

本題に入る前にExifについて


ExifはExchangeable image file formatと呼ばれる写真にメタデータを埋め込むための画像ファイル形式です。
撮影した画像に、例えば、撮影日時、何のデバイスを用いて撮影されたのか、解像度などなど、、、etcが撮影時に付加されてたり、自身で情報を追加することもできます。
データ管理や写真の保存にこの情報が使用されています。」


もう1つ本題に入る前になんで、AVFoundation?

→あまり記事がなかったからです。ほとんどの記事がUIImagePickerControllerを使用した解説、xcodeプロジェクトに既存の.jpg画像をぶち込んでExif情報を扱っていたりで実際に自身が求めていたAVFoundationを使用した際の方法がなかったからです。(特に情報を書き込む方法の方であんまりなかったと思っています。)
→もう1つは古い ALAssetsLibraryフレームワークを使用した記事が多かったからです。非推奨のフレームワークを使用するわけにはいかないので、今できる方法を知りたかったからです。


ってことで、本題。

まずはExif情報を取得してみようーー

Exif情報を取得するには撮影した画像データをもとにCIImageを生成します。
CIImageのpropertiesでその画像データのExif情報をすべて取得できます。

実際に取得したデータは以下の感じです。

f:id:jksdaba:20180504071358p:plain

f:id:jksdaba:20180504071410p:plain

こんな感じでコンソールに出力されます。
JSONみたいな感じですねー

取得するときのコードは以下の感じです。(AVCapureSessionなどのカメラ起動時のコードは省略しています。)

extension CameraViewController: CameraButtonDelegate, AVCapturePhotoCaptureDelegate {
    
    func takePicture() {
        let settings = AVCapturePhotoSettings()
        output.capturePhoto(with: settings, delegate: self)
    }
    
    func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
        if let imageData = photo.fileDataRepresentation() {
            
            let ciImage = CIImage(data: imageData)
            print(ciImage?.properties)


 //以下省略


CIImageのpropertiesプロパティが画像に含まれているメタデータを持っていますので、それをprintで出力してみました。


特定のExif情報を取得するときは以下の感じで取得できます。

extension CameraViewController: CameraButtonDelegate, AVCapturePhotoCaptureDelegate {
    
    override func viewDidAppear(_ animated: Bool) {
        captureButton.delegate = self
    }
    
    func takePicture() {
        print("delegate")
        let settings = AVCapturePhotoSettings()
        output.capturePhoto(with: settings, delegate: self)
    }
    
    func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
        if let imageData = photo.fileDataRepresentation() {
            
            let ciImage = CIImage(data: imageData)
            //print(ciImage?.properties)
            
            if let wrappedCiImage = ciImage {
                //全取得
                print(wrappedCiImage.properties)
                print("-----------------------")
                
                let metaData = wrappedCiImage.properties
                
                let exifData = metaData[kCGImagePropertyExifDictionary as String] as? [String: Any]
                
                if let wrappedExifData = exifData {
                    //トップのキー("{Exif}")にある情報をすべて取得
                    print(wrappedExifData)
                    print("-----------------------")
                    
                    if let pixelX = wrappedExifData[kCGImagePropertyExifPixelXDimension as String] as? Int {
                        
                        //Exifキーの下の階層にいるPixelXDimensionを取得
                        print(pixelX)
                        print("-----------------------")
                    }
                }
            }
            //以下省略

最初に載せたciImage.propertiesが[String: Any]?型だったため、アンラップしてます。その他の特定の辞書についてもアンラップしてから出力させてみました。

上記のコードでのコンソールはこんな感じです。
※print(wrappedExifData)とprint(pixelX)のみのコンソール結果を載せています

f:id:jksdaba:20180504074457p:plain


kCGImagePropertyExifDictionaryはExifを使用するためにある辞書です。
これは実際に出力されたキーの名前と1対1の関係になっています。

出力された時のキー名は以下のように対応しています、、、
kCGImagePropertyExifDictionary - "{Exif}"
kCGImagePropertyExifPixelXDimension - "PixelXDimension"

kCGImagePropertyExifDictionaryなどはImageI/Oフレームワークでグローバルに提供されています。
EXIF Dictionary Keys | Apple Developer Documentation



ちょっと長くなったし、疲れたので、、、
次回Exifに値を追加してみたいと思います。