iOS 8照片框架。 访问照片元数据

我正在寻找replaceALAssetsLibrary与我的应用程序中的照片框架。 我可以检索照片,collections集和资产来源(甚至把它们写回去),但没有看到任何地方访问照片的元数据(诸如{Exif},{TIFF},{GPS},等等…)。 ALAssetsLibrary有一个方法。 UIImagePickerController有一个方法。 照片必须有一个方法。

我看到,PHAsset有一个位置属性,这将为GPS字典,但我期待访问所有的元数据,其中包括,面孔,方向,曝光,ISO和吨更多。

目前苹果正处于testing阶段2.也许还有更多的API来?

UPDATE ————————————————- —————–

没有正式的方法来使用照片API来做到这一点。 但是,您可以在下载图像数据后阅读元数据。 有两种方法可以使用PHImageManager或PHContentEditingInput来完成此操作。 PHContentEditingInput方法需要较less的代码,不需要导入ImageIO。 我把它包装在一个PHAsset类别中

如果您请求内容编辑input,则可以将完整图像作为CIImage ,并且CIImage具有名为properties ,该properties是包含图像元数据的字典。

示例Swift代码:

 let options = PHContentEditingInputRequestOptions() options.networkAccessAllowed = true //download asset metadata from iCloud if needed asset.requestContentEditingInputWithOptions(options) { (contentEditingInput: PHContentEditingInput?, _) -> Void in let fullImage = CIImage(contentsOfURL: contentEditingInput!.fullSizeImageURL) print(fullImage.properties) } 

示例Objective-C代码:

 PHContentEditingInputRequestOptions *options = [[PHContentEditingInputRequestOptions alloc] init]; options.networkAccessAllowed = YES; //download asset metadata from iCloud if needed [asset requestContentEditingInputWithOptions:options completionHandler:^(PHContentEditingInput *contentEditingInput, NSDictionary *info) { CIImage *fullImage = [CIImage imageWithContentsOfURL:contentEditingInput.fullSizeImageURL]; NSLog(@"%@", fullImage.properties.description); }]; 

你会得到所需的{Exif},{TIFF},{GPS}等字典。

我以为我会分享一些代码来使用ImageIO框架和Photos框架来读取元数据。 您必须使用PHCachingImageManager请求图像数据。

 @property (strong) PHCachingImageManager *imageManager; 

请求图像并使用它的数据来创build元数据字典

 -(void)metadataReader{ PHFetchResult *result = [PHAsset fetchAssetsInAssetCollection:self.myAssetCollection options:nil]; [result enumerateObjectsAtIndexes:[NSIndexSet indexSetWithIndex:myIndex] options:NSEnumerationConcurrent usingBlock:^(PHAsset *asset, NSUInteger idx, BOOL *stop) { [self.imageManager requestImageDataForAsset:asset options:nil resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) { NSDictionary *metadata = [self metadataFromImageData:imageData]; NSLog(@"Metadata: %@", metadata.description); NSDictionary *gpsDictionary = metadata[(NSString*)kCGImagePropertyGPSDictionary]; if(gpsDictionary){ NSLog(@"GPS: %@", gpsDictionary.description); } NSDictionary *exifDictionary = metadata[(NSString*)kCGImagePropertyExifDictionary]; if(exifDictionary){ NSLog(@"EXIF: %@", exifDictionary.description); } UIImage *image = [UIImage imageWithData:imageData scale:[UIScreen mainScreen].scale]; // assign image where ever you need... }]; }]; } 

将NSData转换为元数据

 -(NSDictionary*)metadataFromImageData:(NSData*)imageData{ CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)(imageData), NULL); if (imageSource) { NSDictionary *options = @{(NSString *)kCGImageSourceShouldCache : [NSNumber numberWithBool:NO]}; CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, (__bridge CFDictionaryRef)options); if (imageProperties) { NSDictionary *metadata = (__bridge NSDictionary *)imageProperties; CFRelease(imageProperties); CFRelease(imageSource); return metadata; } CFRelease(imageSource); } NSLog(@"Can't read metadata"); return nil; } 

这会占用图像的开销,所以它不如列举资源或集合那么快,但至less是这样。

PhotoKit将对元数据的访问限制为PHAsset(location,creationDate,favorite,hidden,modificatonDate,pixelWidth,pixelHeight …)的属性。 原因(我怀疑)是由于iCloud PhotoLibrary的介绍,图像可能不在设备上。 因此整个元数据不可用。 获得完整EXIF / IPTC元数据的唯一方法是首先从iCloud下载原始图像(如果不可用),然后使用ImageIO提取其元数据。

我find更好的解决scheme,并为我工作是:

 [[PHImageManager defaultManager] requestImageDataForAsset:photoAsset options:reqOptions resultHandler: ^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) { CIImage* ciImage = [CIImage imageWithData:imageData]; DLog(@"Metadata : %@", ciImage.properties); }]; 

您可以使用Photos Framework和UIImagePickerControllerDelegate方法修改PHAsset(例如添加位置元数据)。 没有第三方库的开销,没有创build重复的照片。 适用于iOS 8.0+

在didFinishPickingMediaWithInfo委托方法中,调用UIImageWriteToSavedPhotosAlbum来首先保存图像。 这也将创build我们将要修改EXIF GPS数据的PHAsset:

 func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) { if let myImage = info[UIImagePickerControllerOriginalImage] as? UIImage { UIImageWriteToSavedPhotosAlbum(myImage, self, Selector("image:didFinishSavingWithError:contextInfo:"), nil) } } 

完成select器function将在保存完成后运行或失败并显示错误。 在callback中,获取新创build的PHAsset。 然后,创build一个PHAssetChangeRequest来修改位置元数据。

 func image(image: UIImage, didFinishSavingWithError: NSErrorPointer, contextInfo:UnsafePointer<Void>) { if (didFinishSavingWithError != nil) { print("Error saving photo: \(didFinishSavingWithError)") } else { print("Successfully saved photo, will make request to update asset metadata") // fetch the most recent image asset: let fetchOptions = PHFetchOptions() fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: true)] let fetchResult = PHAsset.fetchAssetsWithMediaType(PHAssetMediaType.Image, options: fetchOptions) // get the asset we want to modify from results: let lastImageAsset = fetchResult.lastObject as! PHAsset // create CLLocation from lat/long coords: // (could fetch from LocationManager if needed) let coordinate = CLLocationCoordinate2DMake(myLatitude, myLongitude) let nowDate = NSDate() // I add some defaults for time/altitude/accuracies: let myLocation = CLLocation(coordinate: coordinate, altitude: 0.0, horizontalAccuracy: 1.0, verticalAccuracy: 1.0, timestamp: nowDate) // make change request: PHPhotoLibrary.sharedPhotoLibrary().performChanges({ // modify existing asset: let assetChangeRequest = PHAssetChangeRequest(forAsset: lastImageAsset) assetChangeRequest.location = myLocation }, completionHandler: { (success:Bool, error:NSError?) -> Void in if (success) { print("Succesfully saved metadata to asset") print("location metadata = \(myLocation)") } else { print("Failed to save metadata to asset with error: \(error!)") }