Someone may think the process is as easy as getting the video from a live photo, removing the video and saving the other parts back. It is wrong.
We can get the video from a live photo using PHAssetResource
's class func assetResources(for livePhoto: PHLivePhoto) -> [PHAssetResource]
. But the PHAssetResource
it gets contains empty assetLocalIdentifier
. So you can't get its asset directly. And you can't remove it separately.
The correct way is to get the photo part, save it and remove the live photo.
Get the photo and save it
We could get the photo in three ways. Two from PHImageManager
and one from PHAssetResourceManager
. However, only one method is right way.
requestImage(for:targetSize:contentMode:options:resultHandler:)
OS, Mac Catalyst, tvOS
func requestImage(for asset: PHAsset, targetSize: CGSize, contentMode: PHImageContentMode, options: PHImageRequestOptions?, resultHandler: @escaping (UIImage?, [AnyHashable : Any]?) -> Void) -> PHImageRequestID
macOS
func requestImage(for asset: PHAsset, targetSize: CGSize, contentMode: PHImageContentMode, options: PHImageRequestOptions?, resultHandler: @escaping (NSImage?, [AnyHashable : Any]?) -> Void) -> PHImageRequestID
We should not use this method as it returns UIImage/NSImage
, according to Apple, those two classes lacks metadata.
A UIImage object does not contain all metadata associated with the image file it was originally loaded from (for example, Exif tags such as geographic location, camera model, and exposure parameters). To ensure such metadata is saved in the Photos library, instead use the
creationRequestForAssetFromImage(atFileURL:)
method or thePHAssetCreationRequest
class. To copy metadata from one file to another, see Image I/O.
creationRequestForAsset(from:)
requestData(for:options:dataReceivedHandler:completionHandler:)
We cannot use requestData(for:options:dataReceivedHandler:completionHandler:)
of PHAssetResourceManager
either. It does return Data
instead of UIImage/NSImage
. But the data it returns cannot save to PHPhotoLibrary
correctly.
I think it is because of the data it returns contains the same
localIdentifier
as the live photo, which is allowed to save separately.
requestImageDataAndOrientation(for:options:resultHandler:)
This is the only way we should use to save the photo part from a live photo.
Remove the live photo
This is an easy job. Just use PHAssetChangeRequest.deleteAssets(_ assets: NSFastEnumeration)
.