Swift如何修改从移动摄像头拍摄的图像中的exif信息

我使用UIImagePickerController来select我的iOS应用程序中的图像,我知道exif信息可以通过信息[UIImagePickerControllerMediaMetadata]得到。 但是当我通过UIImage将我的图像上传到我的服务器时,绝大多数的exif信息都被分割了。 我不知道我是否可以在HTTP请求中添加exif信息到我的图片(之后以jpg格式上传的图片)。 如果不是,我该如何解决这个问题? 我想改变Make,Model属性(换句话说,用什么设备拍这张照片)

以下是我的代码片段:

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) myActivityIndicator.startAnimating() let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in if error != nil { print("error=\(error)") return } // You can print out response object print("******* response = \(response)") // Print out response body let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding) print("****** response data = \(responseString!)") do{ let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSDictionary }catch{ print(error) } dispatch_async(dispatch_get_main_queue(),{ self.myActivityIndicator.stopAnimating() self.myImageView.image = nil }) } task.resume() } 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("--\(boundary)\r\n") body.appendString("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n") body.appendString("\(value)\r\n") } } let filename = "test.jpg" let mimetype = "image/jpg" body.appendString("--\(boundary)\r\n") body.appendString("Content-Disposition: form-data; name=\"\(filePathKey!)\"; filename=\"\(filename)\"\r\n") body.appendString("Content-Type: \(mimetype)\r\n\r\n") body.appendData(imageDataKey) body.appendString("\r\n") body.appendString("--\(boundary)--\r\n") return body } func generateBoundaryString() -> String { return "Boundary-\(NSUUID().UUIDString)" } extension NSMutableData { func appendString(string: String) { let data = string.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true) appendData(data!) } } 

是! 最后我做了一个窍门来修改EXIF信息。 起初,你可以通过UIImageJPEGRepresentation从UIImage获取EXIF信息[UIImagePickerControllerMediaMetadata]和没有EXIF的NSData。 然后,您可以使用修改的EXIF信息创build一个新的NSDictionary。 之后,在下面调用我的函数,你可以得到带有修改EXIF的图像NSData!

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

SWIFT 3

如果您捕捉video并获取CMSampleBuffer,则可以更新EXIF元数据。 在我的情况下,在iOS9我没有得到DateTimeOriginal,虽然在iOS10的DataTimeOriginal已经在。因此,我不得不把几个额外的键值。

 self.stillCameraOutput.captureStillImageAsynchronously(from: connectionVideo) { (sampleBuffer, err) in if let err = err { blockCompletion(nil, err as NSError?) } else { if let sampleBuffer = sampleBuffer { let rawMetadata = CMCopyDictionaryOfAttachments(nil, sampleBuffer, CMAttachmentMode(kCMAttachmentMode_ShouldPropagate)) let metadata = CFDictionaryCreateMutableCopy(nil, 0, rawMetadata) as NSMutableDictionary let exifData = metadata.value(forKey: "{Exif}") as? NSMutableDictionary print("EXIF DATA: \(exifData)") if let dateTime = exifData?["DateTimeOriginal"] as? String { print("DateTime exists \(dateTime)") } else { exifData?.setValue(Date().exifDate(), forKey: "DateTimeOriginal") } if let dateTime = exifData?["DateTimeDigitized"] as? String { print("DateTime exists \(dateTime)") } else { exifData?.setValue(Date().exifDate(), forKey: "DateTimeDigitized") } metadata.setValue(exifData, forKey: "{Exif}") CMSetAttachments(sampleBuffer, metadata as CFDictionary, CMAttachmentMode(kCMAttachmentMode_ShouldPropagate)) let rawMetadata2 = CMCopyDictionaryOfAttachments(nil, sampleBuffer, CMAttachmentMode(kCMAttachmentMode_ShouldPropagate)) let metadata2 = CFDictionaryCreateMutableCopy(nil, 0, rawMetadata2) as NSMutableDictionary let exifData2 = metadata2.value(forKey: "{Exif}") as? NSMutableDictionary print("EXIF DATA: \(exifData2)") if let dataImage = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer) { blockCompletion(dataImage, nil) } else { blockCompletion(nil, nil) } } else { blockCompletion(nil, nil) } } }