🖼️

SwiftUI PhotosPicker で画像の Asset metadata を取得する

2024/08/26に公開

ImagePickerViewController -> PHPickerViewController -> PhotosPicker が ios16 から使用可能になり、PHPikcer 以降はユーザーにフォトライブラリへのフルアクセス or 選択した画像のみのアクセスなどのアクセス許可を得なくても、その場で選択した画像のみの情報を取得できるようになった。

ただしこの PhotosPicker を使いつつ、画像メタデータ(Exif等)を取得する方法が見当たらなかったのでメモ。

なお画像の creationDate については PHAsset 経由でフォトライブラリにアクセスしなければならず、許可無しでの取得はできないが exif や tiff の中に大体は含まれている。

ベースは Apple 公式のデモプロジェクト2つなので、それぞれ Download ボタンからダウンロードして動かしながら試すのがおすすめ。

Base Code

PhotosPicker example:

https://developer.apple.com/documentation/photokit/bringing_photos_picker_to_your_swiftui_app

Load Asset Metadata example:

PHPickerViewController を使った例
https://developer.apple.com/documentation/photokit/selecting_photos_and_videos_in_ios

Get image asset (metadata)

        private func loadTransferable(from imageSelection: PhotosPickerItem) -> Progress {
            return imageSelection.loadTransferable(type: Data.self) { result in
                DispatchQueue.main.async {
                    guard imageSelection == self.imageSelection else {
                        print("Failed to get the selected item.")
                        return
                    }
                    switch result {
                    case .success(let data):
                        guard let data, let uiImage = UIImage(data: data) else {
                            print("Error: Failed to create UIImage from data")
                            return
                        }
                        self.pickedImage = PickedImage(uiImage: uiImage)
    
                        guard let cgImageSource = CGImageSourceCreateWithData(data as CFData, nil),
                              let properties = CGImageSourceCopyPropertiesAtIndex(cgImageSource, 0, nil) else {
                            print("Error: Failed to load image metadata")
                            return
                        }
                        print(properties)
                    case .failure(let error):
                        self.imageState = .failure(error)
                    }
                }
            }
        }

その他

上記のサンプルのように PHPicker で itemProvider 経由でメタデータを取ることも可能だったが、データの節約(ストレージ最適化)のために iCloud からダウンロードしてこなければならない画像は、モバイル通信やオフライン時に取得失敗してしまう。

ImagePicker だと「iCloud からダウンロード中..」のように表示が出てから pick してくれるのだが、PHPicker ではエラーハンドリングの方法すらわからなかった。

Discussion