Applying metadata to image causes performChanges request to fail

限于喜欢 提交于 2019-12-03 15:04:02

问题


I am using PhotoKit to edit photos and I need to preserve the metadata from the original photo. To do so I save the metadata then provide it to the options parameter in CGImageDestinationAddImage. I am able to finalize it and write it to disk successfully, but when I call performChanges to commit the asset edit, it fails. If I instead provide nil for options it will succeed. What is going wrong here?

asset.requestContentEditingInputWithOptions(options) { (input: PHContentEditingInput!, _) -> Void in
    //get full image
    let url = input.fullSizeImageURL
    let inputImage = CIImage(contentsOfURL: url)

    //get orginal photo's metadata
    let originalImageData = NSData(contentsOfURL: url)!
    let imageSource = CGImageSourceCreateWithData(originalImageData, nil)
    let metadata: CFDictionaryRef = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil)
    println(metadata) //prints all the metadata, yay!

    //do some processing on original photo here and create an output CIImage...

    //save to disk
    let dataRef = CFDataCreateMutable(nil, 0)
    let destination = CGImageDestinationCreateWithData(dataRef, CGImageSourceGetType(imageSource), 1, nil)
    let eaglContext = EAGLContext(API: .OpenGLES2)
    let ciContext = CIContext(EAGLContext: eaglContext)
    let cgImage = ContextStruct.ciContext!.createCGImage(outputPhoto, fromRect: outputPhoto.extent())
    CGImageDestinationAddImage(destination, cgImage, metadata) //metadata is problematic - replacing with nil causes it to work

    if CGImageDestinationFinalize(destination) {
        let contentEditingOutput = PHContentEditingOutput(contentEditingInput: input)
        contentEditingOutput.adjustmentData = "something"

        let imageData: NSData = dataRef
        let success = imageData.writeToURL(contentEditingOutput.renderedContentURL, options: .AtomicWrite, error: _)
        if success {
            PHPhotoLibrary.sharedPhotoLibrary().performChanges({ () -> Void in
                let request = PHAssetChangeRequest(forAsset: asset)
                request.contentEditingOutput = contentEditingOutput
            }, completionHandler: { (success: Bool, error: NSError!) -> Void in
                if success == false { println('failed to commit image edit: \(error)') } //fails unless metadata is replaced with nil above
            })
        }
    }
})

The error is: Error Domain=NSCocoaErrorDomain Code=-1 "The operation couldn’t be completed. (Cocoa error -1.)


回答1:


It seems that filling the adjustementData property of the PHContentEditingOutput object is mandatory in order to edit a photo.




回答2:


Certain keys in the metadata seem to cause failure. This works:

NSArray *validMetadataKeys = @[
    (NSString *)kCGImagePropertyTIFFDictionary,
    (NSString *)kCGImagePropertyGIFDictionary,
    (NSString *)kCGImagePropertyJFIFDictionary,
    (NSString *)kCGImagePropertyExifDictionary,
    (NSString *)kCGImagePropertyPNGDictionary,
    (NSString *)kCGImagePropertyIPTCDictionary,
    (NSString *)kCGImagePropertyGPSDictionary,
    (NSString *)kCGImagePropertyRawDictionary,
    (NSString *)kCGImagePropertyCIFFDictionary,
    (NSString *)kCGImageProperty8BIMDictionary,
    (NSString *)kCGImagePropertyDNGDictionary,
    (NSString *)kCGImagePropertyExifAuxDictionary,
];

NSMutableDictionary *validMetadata = [NSMutableDictionary dictionary];
[metadata enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
    if ([validMetadataKeys containsObject:key]) {
        validMetadata[key] = obj;
    }
}];

// your CGImage stuff

CGImageDestinationAddImageFromSource(destination, imgSource, 0, (__bridge CFDictionaryRef)validMetadata);



回答3:


I have exactly the same problem, and I have filed a radar rdar://21057247. I try to log a case using TSI but I have been told to file a radar instead.




回答4:


We are supposed to write the data for the new image to the URL we obtain via

                let theExportURL = output.renderedContentURL

In my case i was doing this...

                let outputData = UIImagePNGRepresentation(bakedImage)

And at runtime i was getting the error

Error Domain=NSCocoaErrorDomain Code=-1 "The operation couldn’t be completed. (Cocoa error -1.)

But when I started exporting the data like this...

let outputData = UIImageJPEGRepresentation(bakedImage, 1)

It worked. This is documented here ... https://developer.apple.com/library/prerelease/ios/documentation/Photos/Reference/PHContentEditingOutput_Class/index.html

and this same question has been answered here... https://stackoverflow.com/a/28362235




回答5:


// if the asset does not allow the type of change requested, these methods will raise an exception, call canPerformEditOperation: on the asset to determine if the type of edit operation is allowed.

  • (instancetype)changeRequestForAsset:(PHAsset *)asset;

I think it's because Apple don't want you to change the metaData.You can try this method below,maybe create a new one is allowed.

  • (instancetype)creationRequestForAssetFromImage:(UIImage *)image;
  • (instancetype)creationRequestForAssetFromImageAtFileURL:(NSURL *)fileURL;
  • (instancetype)creationRequestForAssetFromVideoAtFileURL:(NSURL *)fileURL;


来源:https://stackoverflow.com/questions/28267435/applying-metadata-to-image-causes-performchanges-request-to-fail

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!