SuperBi SuperBi - 3 months ago 66
iOS Question

Swift how to modify exif info in images taken from mobile camera

I use UIImagePickerController to pick images in my iOS App and I know exif info can be got by info[UIImagePickerControllerMediaMetadata]. But when I upload my image to my server by UIImage, most of exif info has been striped. I wonder whether I can add exif info to my image in Http request(image uploaded as jpg after that). If not, how should I solve this problem? I wanna change Make, Model attributes(in other words, what device was used to take this picture)

Below are my code snippets:

func Tapped() {
let myPickerController = UIImagePickerController()

myPickerController.delegate = self
myPickerController.sourceType = UIImagePickerControllerSourceType.Camera
myPickerController.allowsEditing = false
self.presentViewController(myPickerController, animated: true, completion: nil)
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let image = info[UIImagePickerControllerOriginalImage] as? UIImage
myImageView.image = image
UIImageWriteToSavedPhotosAlbum(image!, self, #selector(ViewController.image(_:didFinishSavingWithError:contextInfo:)), nil)
self.dismissViewControllerAnimated(true, completion: nil)

func myImageUploadRequest()

let myUrl = NSURL(string: "http://XXXXXX/Uploadfile")

let request = NSMutableURLRequest(URL:myUrl!)
request.HTTPMethod = "POST"

let param = [
"userId" : "7"

let boundary = generateBoundaryString()

request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

let imageData = UIImageJPEGRepresentation(myImageView.image!, 1)

if(imageData == nil) { return; }

request.HTTPBody = createBodyWithParameters(param, filePathKey: "file", imageDataKey: imageData!, boundary: boundary)


let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in

if error != nil {

// You can print out response object
print("******* response = \(response)")

// Print out response body
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("****** response data = \(responseString!)")

let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSDictionary


self.myImageView.image = nil



func createBodyWithParameters(parameters: [String: String]?, filePathKey: String?, imageDataKey: NSData, boundary: String) -> NSData {
let body = NSMutableData();

if parameters != nil {
for (key, value) in parameters! {
body.appendString("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")

let filename = "test.jpg"

let mimetype = "image/jpg"

body.appendString("Content-Disposition: form-data; name=\"\(filePathKey!)\"; filename=\"\(filename)\"\r\n")
body.appendString("Content-Type: \(mimetype)\r\n\r\n")


return body

func generateBoundaryString() -> String {
return "Boundary-\(NSUUID().UUIDString)"

extension NSMutableData {

func appendString(string: String) {
let data = string.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)


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))

    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! ")