6

I'm trying to do the equivalent of writeImageToSavedPhotosAlbum with the new Photo framework.

To save the image, I only do this:

func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {

    let image = info[UIImagePickerControllerOriginalImage] as UIImage

    PHPhotoLibrary.sharedPhotoLibrary().performChanges({ () -> Void in
              let changeRequest = PHAssetChangeRequest.creationRequestForAssetFromImage(image)
            }, completionHandler: { (success, error) -> Void in
              //
            })
}

Of course, there's no magic and since I don't do anything of

info[UIImagePickerControllerMediaMetadata]

, the above code doesn't save any metadata to the "Camera Roll", as you can see using the screenshot of the Preview.app when I connect my iPhone to my Mac.

enter image description here

You get that view by opening Preview.app, selecting File > Import from "you device name"; then you can browse your pictures and see that those taken with the Camera app show exif data such as focal length, while those saved with the above code show empty values.

Now the documentation for creationRequestForAssetFromImage says:

To set metadata properties of the newly created asset, use the corresponding properties of the change request (listed in Modifying Assets).

Which links to "+changeRequestForAsset:" and 4 properties (creationDate, location, favorite, hidden), that's a little light. What about the other properties one might want to save (like aperture, focal length, shutter speed, …)?

How are you supposed to save your meta data along the image with the Photo framework?

Arnaud
  • 17,268
  • 9
  • 65
  • 83

1 Answers1

3

Here's what I ended up doing:

extension UIImage {

  /**
  Gets the metadata from the photo album

  :param: info The picker dictionary
  :param: completionHandler A block to call when the metadata is available
  */
  class func requestMetadata(info: [NSObject : AnyObject], completionHandler: ([NSObject : AnyObject]) -> Void) {
      let assetUrl = info[UIImagePickerControllerReferenceURL] as! NSURL
      let result = PHAsset.fetchAssetsWithALAssetURLs([assetUrl], options: nil)
      if let asset = result.firstObject as? PHAsset {
        let editOptions = PHContentEditingInputRequestOptions()
        editOptions.networkAccessAllowed = true

        asset.requestContentEditingInputWithOptions(editOptions, completionHandler: { (contentEditingInput, _) -> Void in
            let url = contentEditingInput.fullSizeImageURL
            let orientation = contentEditingInput.fullSizeImageOrientation
            var inputImage = CoreImage.CIImage(contentsOfURL: url)
            completionHandler(inputImage.properties())
        })
    } else {
        completionHandler([:])
    }
  }
}
Arnaud
  • 17,268
  • 9
  • 65
  • 83
  • 1
    Bit confused how that works with didFinishPickingMediaWithInfo and saving the image to file, where do you call that func from? – Steve Jun 12 '15 at 14:53
  • didFinishPickingMediaWithInfo returns info: [NSObject : AnyObject], just call requestMetadata with that value – Arnaud Jun 12 '15 at 15:39
  • What about saving the image to the Camera Roll together with the metadata, how do you make that happen? – mirceapasoi Jul 22 '15 at 21:46
  • Am I right to assume that `completionHandler ` is called when metadata is NOT available? (typo in the func desc?) – Daniel Jul 31 '15 at 19:18
  • 1
    @Daniel this isn't a typo. If firstObject fails, completionHandler is called with an empty dictionary ([:]), otherwise it uses the actual metadata (inputImage.properties()). It's just that in the first case, what's available is … nothing. But it's still available :) – Arnaud Aug 01 '15 at 21:52
  • I see - very elegant. Thanks! – Daniel Aug 02 '15 at 20:10
  • good answer but doesn't saving the picture back with this information. which I assume was the question. I'm look for the same – carbonr Oct 26 '15 at 14:26
  • 1
    @Nycen you can use CoreImage.CIImage instead of the typealias – Leo Dabus Dec 08 '15 at 03:25