I'm using a UIImagePickerController to allow the user to take a picture with the camera. When the delegate's called, I want to save the image to the photo library/camera roll, which I do using PHAssetChangeRequest. The issue is the documentation says I can use the dictionary from UIImagePickerControllerMediaMetadata to include that as metadata, but PHAssetChangeRequest doesn't seem to have a parameter to do this. How can I include this metadata when saving? Thanks!
You can use PHAssetCreationRequest
. In order to use PHAssetCreationRequest
, you will merge imageData and metadata, then write the imageDataWithMetadata to the album. Like this:
if let imageDataWithMetadata = self.writeMetadata(metadata, into: imageData) {
self.saveImageDataForiOS9(imageDataWithMetadata)
}
func saveImageDataForiOS9(_ data: Data) {
var newImageIdentifier: String!
PHPhotoLibrary.shared().performChanges({
if #available(iOS 9.0, *) {
let assetRequest = PHAssetCreationRequest.forAsset()
assetRequest.addResource(with: .photo, data: data, options: nil)
newImageIdentifier = assetRequest.placeholderForCreatedAsset!.localIdentifier
} else {
// Fallback on earlier versions
}
}) { (success, error) in
DispatchQueue.main.async(execute: {
if success, let newAsset = PHAsset.fetchAssets(withLocalIdentifiers: [newImageIdentifi
// ...
} else {
// ...
}
})
}
}
For iOS 8, you can use ALAssetsLibrary
to saving a new image with metadata:
func saveImageDataForiOS8(_ imageData: Data, _ metadata: Dictionary<AnyHashable, Any>?) {
let library = ALAssetsLibrary()
library.writeImageData(toSavedPhotosAlbum: imageData, metadata: metadata, completionBlock: { (newURL, error) in
if let _ = error {
// ...
} else {
if let newAsset = PHAsset.fetchAssets(withALAssetURLs: [newURL!], options: nil).firstObject {
// ...
}
}
})
}
So, finally you will have code like this:
func saveImage(_ imageData: Data, metadata: Dictionary<AnyHashable, Any>?) {
if #available(iOS 9.0, *) {
if let metadata = metadata {
if let imageDataWithMetadata = self.writeMetadata(metadata, into: imageData) {
self.saveImageDataForiOS9(imageDataWithMetadata)
} else {
self.saveImageDataForiOS9(imageData)
}
} else {
self.saveImageDataForiOS9(imageData)
}
} else {
self.saveImageDataForiOS8(imageData, metadata)
}
}
func saveImageDataForiOS8(_ imageData: Data, _ metadata: Dictionary<AnyHashable, Any>?) {
let library = ALAssetsLibrary()
library.writeImageData(toSavedPhotosAlbum: imageData, metadata: metadata, completionBloc
if let _ = error {
// ...
} else {
if let newAsset = PHAsset.fetchAssets(withALAssetURLs: [newURL!], options: nil).
// ...
}
}
})
}
func saveImageDataForiOS9(_ data: Data) {
var newImageIdentifier: String!
PHPhotoLibrary.shared().performChanges({
if #available(iOS 9.0, *) {
let assetRequest = PHAssetCreationRequest.forAsset()
assetRequest.addResource(with: .photo, data: data, options: nil)
newImageIdentifier = assetRequest.placeholderForCreatedAsset!.localIdentifier
} else {
// Fallback on earlier versions
}
}) { (success, error) in
DispatchQueue.main.async(execute: {
if success, let newAsset = PHAsset.fetchAssets(withLocalIdentifiers: [newImageId
// ...
} else {
// ...
}
})
}
}
internal func writeMetadata(_ metadata: Dictionary<AnyHashable, Any>, into imageData: Data)
let source = CGImageSourceCreateWithData(imageData as CFData, nil)!
let UTI = CGImageSourceGetType(source)!
let newImageData = NSMutableData()
if let destination = CGImageDestinationCreateWithData(newImageData, UTI, 1, nil) {
CGImageDestinationAddImageFromSource(destination, source, 0, metadata as CFDictionar
if CGImageDestinationFinalize(destination) {
return newImageData as Data
} else {
return nil
}
} else {
return nil
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With