Metadata (EXIF, TIFF, etc.) in Photokit

2019-03-13 05:49发布

问题:

In iOS 8, with the new PhotoKit, the way to create a new image is with -[PHPhotoLibrary performChanges:completionHandler], in this way:

[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
    PHAssetChangeRequest *changeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
    // TODO set metadata?
} completionHandler:^(BOOL success, NSError *error) {
    if(success)
    {
        // do stuff
    }
}];

However, I can't find any documentation on how to set metadata on the image.

In the old ALAssetLibrary (which still works, and may still be the 'correct' way going forward), you would just use -[ALAssetLibrary writePhotoToSavedPhotosAlbum:metadata:completionBlock:], which allows you to pass in a metadata dictionary.

Is there an equivalent method in PhotoKit?

回答1:

You can achieve the same result by using a temporary file. For example:

import Photos
import ImageIO
import MobileCoreServices

PHPhotoLibrary.sharedPhotoLibrary().performChanges ({
    let temporaryPath = ... // a path in the App's documents or cache directory
    let fileURL = NSURL.fileURLWithPath (temporaryPath)!

    // custom UIImagePNGRepresentation function is implemented below
    let PNGdataWithMetadata = UIImagePNGRepresentation (photo, copyright: "Image Copyright",
                author: "Image Author", description: "Image Description")
    let createAssetRequest = PHAssetChangeRequest.creationRequestForAssetFromImageAtFileURL (fileURL)
}, completionHandler: { (success, error) in
       // to-do: delete the temporary file            
        println ("completion \(success) \(error)")
})

// what the custom UIImagePNGRepresentation function does is create a PNG representation that contains the given metadata. The function assumes all functions return valid data
// to add the metadata to the PNG representation of the image we:
// 1. create the PNG representation and read the default values (these will include things like the image's size)
// 2. add the metadata items (see CGImageProperties Reference for the valid keys)
// 3. create an image destination where the new PNG will be created and assigned the metadata dictionary 

public func UIImagePNGRepresentation (image : UIImage, # copyright : String, # author : String, # description : String) -> NSData {
    // wrap the valid metadata values in a dictionary
    var PNGmetadata = [String : AnyObject] ()
    PNGmetadata [kCGImagePropertyPNGCopyright] = copyright
    PNGmetadata [kCGImagePropertyPNGAuthor] = author
    PNGmetadata [kCGImagePropertyPNGDescription] = description

    let metadata = [kCGImagePropertyPNGDictionary as String : PNGmetadata]
    return UIImagePNGRepresentation (image, metadata: metadata)
}

public func UIImagePNGRepresentation (image : UIImage, # metadata : [String : [String : AnyObject]]) -> NSData {
    let imageSource = CGImageSourceCreateWithData (UIImagePNGRepresentation (image), nil)
    let defaultAttributes = CGImageSourceCopyPropertiesAtIndex (imageSource, 0, nil) as NSDictionary
    let extendedAttributes = defaultAttributes.mutableCopy () as NSMutableDictionary

    for item in metadata {
        extendedAttributes [item.0] = item.1
    }

    var outputPNGdata = NSMutableData ()
    let imageDestination = CGImageDestinationCreateWithData (outputPNGdata, kUTTypePNG, 1, nil)
    CGImageDestinationAddImageFromSource (imageDestination, imageSource, 0, extendedAttributes)
    let success = CGImageDestinationFinalize (imageDestination)
    assert (success, "Fail!")

    return outputPNGdata
}

I'm copying-pasting code from my project, hopefully I'm not missing something.