Swift UIKit Live Photo 다루기

  • 이번에는 애플 생태계(iOS, iPadOS, macOS)에서는 유용하게 사용되는 Live Photo에 대해 알아보겠다.
  • Live Photo는 기본적으로 사진인데, 촬영 순간의 앞뒤 장면도 담겨있다는 특징이 있다.
  • Live Photo를 저장하고 불러오는 방법, 그리고 Video 포맷으로 변환하는 방법을 알아보겠다.

Live Photo 저장하기

  • Live Photo의 구조를 들여다보면, 하나의 Live Photo는 하나의 사진과 하나의 영상으로 이뤄져있다.
  • 그래서 Live Photo를 저장한다고 하면, 한 쌍의 사진과 영상을 저장하는 것과 같다.
  • 이 부분에서는 Live Photo를 사용자의 사진보관함에 저장하는 방법을 알아보겠다.
var livePhotoResource: (pairedImage: URL, pairedVideo: URL)?

self.saveToLibrary(livePhotoResource) { (success) in
    if success {
        print("라이브포토가 사진에 저장되었습니다")
    } else {
        print("에러가 발생했습니다")
    }
}
  • livePhotoResource는 한 쌍의 사진과 영상을 묶은 tuple 타입이다.
  • 다음과 같이 saveToLibrary function에 임의의 livePhotoResource를 넣어 저장하면 된다.
func saveToLibrary(_ resources: LivePhotoResources, completion: @escaping (Bool) -> Void) {
    PHPhotoLibrary.shared().performChanges({
        let creationRequest = PHAssetCreationRequest.forAsset()
        let options = PHAssetResourceCreationOptions()

        creationRequest.addResource(with: PHAssetResourceType.pairedVideo, fileURL: resources.pairedVideo, options: options)
        creationRequest.addResource(with: PHAssetResourceType.photo, fileURL: resources.pairedImage, options: options)
    }, completionHandler: { (success, error) in
        if error != nil {
            print(error as Any)
        }

        completion(success)
    })
}
  • saveToLibrary는 이렇게 생겼는데, 결국 한 쌍의 사진과 영상을 사진보관함에 추가하는 방식이다.

Live Photo 불러오기

  • 이번에는 Live Photo를 사진보관함으로부터 불러오는 방법에 대해 알아보겠다.
let livePhotoVideoURL: URL?

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    if let mediaType = info[UIImagePickerController.InfoKey.mediaType] as? NSString {
        if mediaType == kUTTypeLivePhoto {
            guard let livePhoto = info[UIImagePickerController.InfoKey.livePhoto] as? PHLivePhoto else { return }

            self.extractResources(from: livePhoto, to: someURL, completion: { resources in
                self.livePhotoVideoURL = resources?.pairedVideo
            })
        }
    }
}    
  • 우선, 사진보관함의 내용물을 불러오기 위해 Image Picker를 사용해야 한다.
  • Image Picker는 사용할줄 안다고 가정하고 넘어가겠다.
  • Image Picker의 info를 통해 불러온 미디어가 Live Photo이면, 이를 PHLivePhoto로 캐스팅한다.
  • 캐스팅해서 얻은 값을 extractResources에 넣고, 나온 값이 해당 Live Photo의 URL이다.
func extractResources(from livePhoto: PHLivePhoto, to directoryURL: URL, completion: @escaping (LivePhotoResources?) -> Void) {
    let assetResources = PHAssetResource.assetResources(for: livePhoto)

    var keyPhotoURL: URL?
    var videoURL: URL?

    for resource in assetResources {
        let buffer = NSMutableData()
        let options = PHAssetResourceRequestOptions()

        PHAssetResourceManager.default().requestData(for: resource, options: options, dataReceivedHandler: { (data) in
            buffer.append(data)
        }) { (error) in
            if error == nil {
                if resource.type == .pairedVideo {
                    videoURL = self.saveAssetResource(resource, to: directoryURL, resourceData: buffer as Data)
                } else {
                    keyPhotoURL = self.saveAssetResource(resource, to: directoryURL, resourceData: buffer as Data)
                }
            } else {
                print(error as Any)
            }
        }
    }

    completion((keyPhotoURL!, videoURL!))
}
  • extractResources는 이렇게 생겼다.
  • PHAssetResourceManager의 default()의 requestData 이 부분이 핵심이다.
  • videoURL과 keyPhotoURL을 받아, completion을 통해 튜플 값으로 넘겨주는 것이다.

Live Photo를 Video로

  • 위 내용들을 잘 이해했다면, Live Photo를 Video를 변환하는 것은 의외로 간단하다.
if FileManager.default.fileExists(atPath: livePhotoVideoURL.path) {
    PHPhotoLibrary.shared().performChanges({
        let videoURL = Foundation.URL(fileURLWithPath: livePhotoVideoURL.path)
        PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: videoURL)
    }) { (success, error) -> Void in
        if success {
            print("비디오가 사진에 저장되었습니다")
        } else {
            print(error.debugDescription)
        }
    }
}
  • 앞서, 사진보관함으로부터 Live Photo의 Paired Video URL을 불러왔었다.
  • 해당 URL을 PHPhotoLibrary에 저장하면 끝이다.