Swift how to modify exif info in images taken from mobile camera
Swift 5 Version of the accepted answer -
func saveImageWithImageData(data: NSData, properties: NSDictionary, completion: (_ data: NSData, _ path: NSURL) -> Void) {
let imageRef: CGImageSource = CGImageSourceCreateWithData((data as CFData), nil)!
let uti: CFString = CGImageSourceGetType(imageRef)!
let dataWithEXIF: NSMutableData = NSMutableData(data: data as Data)
let destination: CGImageDestination = CGImageDestinationCreateWithData((dataWithEXIF as CFMutableData), uti, 1, nil)!
CGImageDestinationAddImageFromSource(destination, imageRef, 0, (properties as CFDictionary))
CGImageDestinationFinalize(destination)
let paths: [String] = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let savePath: String = paths[0].appending("exif.jpg")
let manager: FileManager = FileManager.default
manager.createFile(atPath: savePath, contents: dataWithEXIF as Data, attributes: nil)
completion(dataWithEXIF,NSURL(string: savePath)!)
print("image with EXIF info converting to NSData: Done! Ready to upload! ")
}
Yes! Finally I made a trick to modify the EXIF info. At first, you can get EXIF info from info[UIImagePickerControllerMediaMetadata] and NSData without EXIF from picked UIImage by UIImageJPEGRepresentation. Then, you can create a new NSDictionary with modified EXIF info. After that, call my function in the following, you can get image NSData with modified EXIF!
func saveImageWithImageData(data: NSData, properties: NSDictionary, completion: (data: NSData, path: NSURL) -> Void) {
let imageRef: CGImageSourceRef = CGImageSourceCreateWithData((data as CFDataRef), nil)!
let uti: CFString = CGImageSourceGetType(imageRef)!
let dataWithEXIF: NSMutableData = NSMutableData(data: data)
let destination: CGImageDestinationRef = CGImageDestinationCreateWithData((dataWithEXIF as CFMutableDataRef), uti, 1, nil)!
CGImageDestinationAddImageFromSource(destination, imageRef, 0, (properties as CFDictionaryRef))
CGImageDestinationFinalize(destination)
var paths: [AnyObject] = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
let savePath: String = paths[0].stringByAppendingPathComponent("exif.jpg")
let manager: NSFileManager = NSFileManager.defaultManager()
manager.createFileAtPath(savePath, contents: dataWithEXIF, attributes: nil)
completion(data: dataWithEXIF,path: NSURL(string: savePath)!)
print("image with EXIF info converting to NSData: Done! Ready to upload! ")
}
using and mergind some info from other posts, I approached problem using Dictionary in Swift. I used it in captureOutput of AVFounfation callback for AVCapturePhoto:
func photoOutput(_ output: AVCapturePhotoOutput,
didFinishProcessingPhoto photo: AVCapturePhoto,
error: Error?) {
//retrieve exif information
var photoFormatDescription: CMFormatDescription?
CMVideoFormatDescriptionCreateForImageBuffer(kCFAllocatorDefault, photoPixelBuffer, &photoFormatDescription)
var metadataAttachments: Dictionary = photo.metadata as Dictionary
if var exifData = metadataAttachments["{Exif}"] as? [String: Any] {
exifData[kCGImagePropertyExifUserComment as String] = "<whatever you want to write>"
metadataAttachments[kCGImagePropertyExifDictionary as String] = exifData
}
}
After that "metadataAttachments" is used to build final image (using CGImageDestinationAddImage in my case)
It seems to work (tried in a project build with Swift 4.0)
Hope it can help!