Edição de metadados da foto e PHAdjustmentData
A função a seguir carrega uma foto, edita os metadados exif anexados a ela e salva-os novamente. A função parece funcionar apenas para fotos que já possuem um PHAdjustmentData anexado, ou seja, fotos que foram editadas com outro aplicativo anteriormente. Se uma foto não foi editada, ela falha no bloco performChanges () e imprime
Failed to save. Error: Optional(Error Domain=NSCocoaErrorDomain Code=-1 "(null)").
Por que falha nesta situação? Examinando o estouro de pilha, vi várias outras versões dessa questão, mas nenhuma delas parecia ter sido resolvida. Sei que isso falhará se a imagem salva for PNG, mas minha imagem original é JPEG, portanto, a imagem salva também é JPEG.
func editPhotoProperties(_ asset: PHAsset) {
let options = PHContentEditingInputRequestOptions()
options.canHandleAdjustmentData = { data in
return false
}
asset.requestContentEditingInput(with: options) { input, info in
if let input = input {
let adjustmentData = PHAdjustmentData(formatIdentifier:"viewfinder", formatVersion:"1.0", data:"viewfinder".data(using:.utf8)!)
let output = PHContentEditingOutput(contentEditingInput:input)
output.adjustmentData = adjustmentData
do {
let imageData = try Data(contentsOf:input.fullSizeImageURL!)
} catch {
print("Failed to load data")
return
}
let properties = getImageDataProperties(imageData)!
let properties2 = properties.mutableCopy() as! NSMutableDictionary
// edit properties2
...
let newImageData = addImageProperties(imageData: imageData, properties: properties2)
do {
try newImageData!.write(to: output.renderedContentURL, options: .atomic)
} catch {
print("Failed to write to disk")
return
}
PHPhotoLibrary.shared().performChanges({
let changeRequest = PHAssetChangeRequest(for:asset)
changeRequest.contentEditingOutput = output
}) { success, error in
if !success {
print("Failed to save. Error: \(String(describing:error))")
}
}
}
}
}
func getImageDataProperties(_ data: Data) -> NSDictionary? {
if let imageSource = CGImageSourceCreateWithData(data as CFData, nil) {
if let dictionary = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) {
return dictionary
}
}
return nil
}
// add image properties (exif, gps etc) to image
func addImageProperties(imageData: Data, properties: NSDictionary?) -> Data? {
// create an imagesourceref
if let source = CGImageSourceCreateWithData(imageData as CFData, nil) {
// this is of type image
if let uti = CGImageSourceGetType(source) {
// create a new data object and write the new image into it
let destinationData = NSMutableData()
if let destination = CGImageDestinationCreateWithData(destinationData, uti, 1, nil) {
// add the image contained in the image source to the destination, overidding the old metadata with our modified metadata
CGImageDestinationAddImageFromSource(destination, source, 0, properties)
if CGImageDestinationFinalize(destination) == false {
return nil
}
return destinationData as Data
}
}
}
return nil
}