2016-06-23 18 views
5

Ich benutze UIImagePickerController, um Bilder in meiner iOS App auszuwählen, und ich weiß exif Informationen können durch Info [UIImagePickerControllerMediaMetadata] erhalten werden. Aber wenn ich mein Image von UIImage auf meinen Server hochlade, wurden die meisten Exif-Informationen gestreift. Ich frage mich, ob ich exif Informationen zu meinem Bild in Http Anfrage hinzufügen kann (Bild als jpg danach hochgeladen). Wenn nicht, wie soll ich dieses Problem lösen? Ich will Änderung vornehmen, Modell-Attribute (in anderen Worten, was Gerät wurde verwendet, um dieses Bild zu machen)Swift, wie Exif Informationen in Bildern aus der mobilen Kamera geändert werden

Hier sind meine Code-Schnipsel:

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!) 
} 
} 
+0

Irgendwelche Updates zu diesem Thema? Ich kann auch keine einfache Methode finden, dies zu tun. – jonmecer

Antwort

2

Ja! Schließlich habe ich einen Trick gemacht, um die EXIF-Informationen zu modifizieren. Zuerst können Sie EXIF-Informationen von Info [UIImagePickerControllerMediaMetadata] und NSData ohne EXIF ​​von Picked UIImage by UIImageJPEGRepresentation abrufen. Anschließend können Sie ein neues NSDictionary mit geänderten EXIF-Informationen erstellen. Danach, rufen Sie meine Funktion im folgenden, können Sie Bild NSData mit modifizierten EXIF ​​erhalten!

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

} 
0

SWIFT 3

Falls Sie sich eine Videoaufnahme und die CMSampleBuffer immer es eine Möglichkeit ist, die EXIF-Metadaten zu aktualisieren. In meinem Fall in iOS9 habe ich nicht das Aufnahmedatum erhalten, obwohl in iOS10 die DataTimeOriginal war bereits in. So musste ich in wenigen zusätzlichen Schlüsselwerte setzen.

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) 
      } 
     } 
    } 
+0

Ich habe diese Methode versucht, aber meine RawMetadata ist Null. Funktioniert das bei Bilddaten von AVCapturePhotoOutput? –

+0

http://stackoverflow.com/questions/43489623/geotag-images-from-image-picker-swift-3 können Sie auch dies –

1

mit und ein paar Informationen von anderen Beiträgen mergind, Ich habe das Problem mit Dictionary in Swift angesprochen. Ich benutzte es in captureOutput von AVFounfation Rückruf für 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 
    } 

} 

Nach dass „metadataAttachments“ verwendet wird Endbild zu bauen (mit CGImageDestinationAddImage in meinem Fall)

Es scheint in einem Projekt bauen zu arbeiten (versucht mit Swift 4.0)

Hoffe es kann helfen!