In my app I have a section of code where I need to account for a PHLivePhoto type object and convert this to a UIImage. I believe it has to do with a PHAsset
, PHAssetResource
, or PHImageManager
but unclear how to perform the conversion. What's a good approach on how to convert from PHLivePhoto -> UIImage? Thanks for the help!
if let livePhoto = object as? PHLivePhoto {
let livePhotoResources = PHAssetResource.assetResources(for: livePhoto)
print("\(livePhotoResources)")
// imageBucket is of type UIImage[]
// livePhoto is of type PHLivePhoto but I don't know how to convert this to type PHAsset
viewModel.imageBucket.append(convertImageAsset(asset: **WHAT_DO_I_INSERT_HERE**))
}
...
func convertImageAsset(asset: PHAsset) -> UIImage {
let manager = PHImageManager.default()
let option = PHImageRequestOptions()
var tmpImage = UIImage()
option.isSynchronous = true
manager.requestImage(
for: asset,
targetSize: CGSize(width: asset.pixelWidth, height: asset.pixelHeight),
contentMode: .aspectFit,
options: option,
resultHandler: {(result, info)->Void in
tmpImage = result!
})
return tmpImage
}
results in:
[<PHAssetResource: 0x28225cdc0> {
type: photo
uti: public.heic
filename: IMG_5442.heic
asset: (null)
locallyAvailable: YES
fileURL: file:///private/var/mobile/Containers/Data/Application/2FB56305-7600-4A8E-9C67-A71B4A4A9607/tmp/live-photo-bundle/75FD3D97-F13E-4F79-A6E9-F0743D443FDD.pvt/IMG_5442.HEIC
width: 0
height: 0
fileSize: 0
analysisType: unavailable
cplResourceType: Unknown
isCurrent: NO
isInCloud: NO
}, <PHAssetResource: 0x28226bc00> {
type: video_cmpl
uti: com.apple.quicktime-movie
filename: IMG_5442.mov
asset: (null)
locallyAvailable: YES
fileURL: file:///private/var/mobile/Containers/Data/Application/2FB56305-7600-4A8E-9C67-A71B4A4A9607/tmp/live-photo-bundle/75FD3D97-F13E-4F79-A6E9-F0743D443FDD.pvt/IMG_5442.MOV
width: 0
height: 0
fileSize: 0
analysisType: unavailable
cplResourceType: Unknown
isCurrent: NO
isInCloud: NO
}]
You need to use PHAsset
to fetch the asset, then request image data from PHImageManager.default()
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
dismiss(animated: true)
guard let assetIdentifier = results.first?.assetIdentifier else {
return
}
if let phAsset = PHAsset.fetchAssets(withLocalIdentifiers: [assetIdentifier], options: nil).firstObject {
PHImageManager.default().requestImageDataAndOrientation(for: phAsset, options: nil) { [weak self] data, _, _, _ in
if let data = data, let image = UIImage(data: data) {
self?.viewModel.imageBucket.append(image)
}
}
}
}
To get assetIdentifier, you need to create PHPickerConfiguration
object using the shared photo library. Creating a configuration without a photo library provides only asset data, and doesn't include asset identifiers.
var configuration = PHPickerConfiguration(photoLibrary: .shared())
// Set the filter type according to the user’s selection. .images is a filter to display images, including Live Photos.
configuration.filter = .images
// Set the mode to avoid transcoding, if possible, if your app supports arbitrary image/video encodings.
configuration.preferredAssetRepresentationMode = .current
// Set the selection limit.
configuration.selectionLimit = 1
let picker = PHPickerViewController(configuration: configuration)
picker.delegate = self
present(picker, animated: true)