10

我正在通过 PhotoKit 编辑照片,但我发现这不会保留原始照片的元数据。即使 Apple 提供的 SamplePhotosApp 在应用 Sepia 或 Chrome 滤镜时也会出现这种情况。我的问题是,您如何确保保留所有原始照片元数据?

我发现了如何获取原始图像的元数据,并且我能够将该元数据保存到CIImage我创建的最终图像中,但是在提交编辑时它仍然会被删除。CIImage我将to a转换为 a CGImageto 的UIImage方式NSData,或者我如何将其写入磁盘的方式肯定存在问题。

asset.requestContentEditingInputWithOptions(options) { (input: PHContentEditingInput!, _) -> Void in
    //Get full image
    let url = input.fullSizeImageURL
    let orientation = self.input.fullSizeImageOrientation
    var inputImage = CIImage(contentsOfURL: url)
    inputImage = inputImage.imageByApplyingOrientation(orientation)

    //do some processing on original photo here and create a CGImage...

    //save the original photo's metadata to a new CIImage:
    let originalMetadata = inputImage.properties()
    let newImage = CIImage(CGImage: editedCGImage, options: [kCIImageProperties: originalMetadata])

    println(newImage.properties()) //correctly prints all metadata!

    //commit changes to disk - somewhere after this line the metadata is lost
    let eaglContext = EAGLContext(API: .OpenGLES2)
    let ciContext = CIContext(EAGLContext: eaglContext)
    let outputImageRef = ciContext.createCGImage(newImage, fromRect: newImage.extent())
    let uiImage = UIImage(CGImage: outputImageRef, scale: 1.0, orientation: UIImageOrientation.Up)
    let jpegNSData = UIImageJPEGRepresentation(uiImage, 0.75)

    let contentEditingOutput = PHContentEditingOutput(contentEditingInput: input)
    let success = jpegData.writeToURL(contentEditingOutput.renderedContentURL, options: NSDataWritingOptions.AtomicWrite, error: _)

    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)') }
    })
})

原始 - 请注意 GPS 选项卡:
原始照片的元数据

编辑照片后:
在此处输入图像描述

4

2 回答 2

5

根据 CIImage.properties 的 Apple 文档:

如果 CIImage 对象是过滤器(或过滤器链)的输出,则此方法从过滤器的原始输入图像返回元数据。

话虽如此,如果文档不正确,我会这样做。

您需要自己保存属性。为此,您需要将 URL 的内容读取为 NSData

NSURL *url = @"http://somewebsite.com/path/to/some/image.jpg";
NSData *imageData = [NSData dataWithContentsOfURL:url];
CIImage *image = [CIImage imageWithData:imageData];

// Save off the properties
CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef) imageData);
NSDictionary* metadata = (__bridge NSDictionary *) CGImageSourceCopyProperties(imageSource, NULL);

// process your image
// ...
NSData *outputData = // create data from altered image.

// Save the image
CGImageSourceRef outputImageSource = CGImageSourceCreateWithData((__bridge CFDataRef) outputData);
CFMutableDataRef jpegData = CFDataCreateMutable(NULL, 0);
CGImageDestinationRef outputDestination = CGImageDestinationCreateWithData(jpegData, CGImageSourceGetType(outputImageSource), 1, NULL);

// add the image data to the destination
CGImageDestinationAddImageFromSource(jpegData, outputImageSource, 0, (__bridge CFDictionaryRef) metadata);

if (CGImageDestinationFinalize(outputDestination)) {
    NSLog(@"Successful image creation.");
    // process the image rendering, adjustment data creation and finalize the asset edit.
} else {
    NSLog(@"Image creation failed.");
}

如果您不需要修改元数据,则无需将 CFDataRef 强制转换为 NSDictionary*,但我在这里只是为了完整性。

于 2014-09-22T01:14:58.230 回答
4

虽然正如 Bradley 所展示的那样,这在 Objective-C 中是可能的,但它在 Swift 中无法正常工作,并且会导致performChanges块失败(请参阅我的另一个问题)。这已在最新版本中解决 - Xcode 6.3 中的 Swift 1.2。要保留元数据,很简单:

let metadata = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as NSDictionary
CGImageDestinationAddImage(destination, cgImage, metadata)

或者对于 Objective-C:

NSMutableDictionary *imageMetadata = [(NSDictionary *) CFBridgingRelease(CGImageSourceCopyPropertiesAtIndex(imageSource, 0, NULL)) mutableCopy];
CGImageDestinationAddImageFromSource(destination, imageSource, 0, (__bridge CFDictionaryRef)(imageMetadata));

编辑:虽然这适用于 iOS 模拟器,但它不适用于运行 Swift 代码的真实设备。

于 2015-05-04T16:04:12.023 回答