使用新的PHPhotoLibrary保存exif元数据

时间:2016-03-02 21:32:59

标签: ios objective-c ios9 phphotolibrary

我目前正在使用"032016"来获取全分辨率照片。我也可以使用以下代码获取exif元数据:

AVCaptureStillImageOutput

元数据位于[self.stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) { CFDictionaryRef metaDict = CMCopyDictionaryOfAttachments(NULL, imageSampleBuffer, kCMAttachmentMode_ShouldPropagate); CFMutableDictionaryRef mutableDict = CFDictionaryCreateMutableCopy(NULL, 0, metaDict); NSLog(@"test attachments %@", mutableDict); // set the dictionary back to the buffer CMSetAttachments(imageSampleBuffer, mutableDict, kCMAttachmentMode_ShouldPropagate); NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer]; UIImage *image = [[UIImage alloc] initWithData:imageData]; [self.delegate frameReadyToSave:image withExifAttachments: mutableDict]; }]; 变量中。现在,我想用两个元数据将这张图片保存在两个不同的地方。我想将它保存在应用程序文件夹和照片库中的磁盘上。

现在,我尝试使用以下方法以另一种方法保存图像(您看到的图像变量是自定义对象):

mutableDict

现在,图像已正确保存,但不包含任何Exif元数据。

从我读过的内容来看,我需要使用PHPhotoLibrary这样做,但文档并不是那么啰嗦。这是我发现的:

NSData* imageData = UIImageJPEGRepresentation(image.image, 1.0f);

[imageData writeToFile:image.filePath atomically:YES];

UIImageWriteToSavedPhotosAlbum(image.image, nil, nil, nil);

但是如何用它保存元数据呢?

2 个答案:

答案 0 :(得分:1)

我建议您使用ImageIO来实现这一目标:

-(void)frameReadyToSave:(UIImage*)image withExifAttachments:(NSMutableDictionary*)mutableDict
{
    NSData* imageData = UIImageJPEGRepresentation(image, 1.0f);
    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef) imageData, NULL);
    __block NSURL* tmpURL = [NSURL fileURLWithPath:@"example.jpg"]; //modify to your needs
    CGImageDestinationRef destination = CGImageDestinationCreateWithURL((__bridge CFURLRef) tmpURL, kUTTypeJPEG, 1, NULL);
    CGImageDestinationAddImageFromSource(destination, source, 0, (__bridge CFDictionaryRef) mutableDict);
    CGImageDestinationFinalize(destination);
    CFRelease(source);
    CFRelease(destination);
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
        [PHAssetChangeRequest creationRequestForAssetFromImageAtFileURL:tmpURL];
    }   completionHandler:^(BOOL success, NSError *error) {
        //cleanup the tmp file after import, if needed
    }];
}

答案 1 :(得分:1)

使用此方法将元数据合并到图像数据中,并将其保存到照片库中:

func saveImageData(data: Data, metadata: NSDictionary? = nil, album: PHAssetCollection, completion:((PHAsset?)->())? = nil) {
    var placeholder: PHObjectPlaceholder?

    PHPhotoLibrary.shared().performChanges({
        var changeRequest: PHAssetChangeRequest

        if let metadata = metadata {
            let newImageData = UIImage.mergeImageData(imageData: data, with: metadata)
            changeRequest = PHAssetCreationRequest.forAsset()
            (changeRequest as! PHAssetCreationRequest).addResource(with: .photo, data: newImageData as Data, options: nil)
        }
        else {
            changeRequest = PHAssetChangeRequest.creationRequestForAsset(from: UIImage(data: data)!)
        }

        guard let albumChangeRequest = PHAssetCollectionChangeRequest(for: album),
            let photoPlaceholder = changeRequest.placeholderForCreatedAsset else { return }

        placeholder = photoPlaceholder
        let fastEnumeration = NSArray(array: [photoPlaceholder] as [PHObjectPlaceholder])
        albumChangeRequest.addAssets(fastEnumeration)
    }, completionHandler: { success, error in
        guard let placeholder = placeholder else {
            completion?(nil)
            return
        }

        if success {
            let assets:PHFetchResult<PHAsset> =  PHAsset.fetchAssets(withLocalIdentifiers: [placeholder.localIdentifier], options: nil)
            let asset:PHAsset? = assets.firstObject
            completion?(asset)
        }
        else {
            completion?(nil)
        }
    })
}

func mergeImageData(imageData: Data, with metadata: NSDictionary) -> Data {
    let source: CGImageSource = CGImageSourceCreateWithData(imageData as NSData, nil)!
    let UTI: CFString = CGImageSourceGetType(source)!
    let newImageData =  NSMutableData()
    let cgImage = UIImage(data: imageData)!.cgImage
    let imageDestination: CGImageDestination = CGImageDestinationCreateWithData((newImageData as CFMutableData), UTI, 1, nil)!
    CGImageDestinationAddImage(imageDestination, cgImage!, metadata as CFDictionary)
    CGImageDestinationFinalize(imageDestination)

    return newImageData as Data
}