iOS 8 Photos framework. Access photo metadata
If you request a content editing input, you can get the full image as a CIImage
, and CIImage
has a property titled properties
which is a dictionary containing the image metadata.
Sample Swift Code:
let options = PHContentEditingInputRequestOptions()options.networkAccessAllowed = true //download asset metadata from iCloud if neededasset.requestContentEditingInputWithOptions(options) { (contentEditingInput: PHContentEditingInput?, _) -> Void in let fullImage = CIImage(contentsOfURL: contentEditingInput!.fullSizeImageURL) print(fullImage.properties)}
Sample Objective-C Code:
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);}];
You'll get the desired {Exif}, {TIFF}, {GPS}, etc dictionaries.
I thought I'd share some code to read the metadata using the ImageIO framework in conjunction with Photos framework. You must request the image data using a PHCachingImageManager.
@property (strong) PHCachingImageManager *imageManager;
Request the image and use it's data to create a metadata dictionary
-(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... }]; }];}
Convert NSData to metadata
-(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;}
This has the overhead of grabbing the image, so it's not nearly as fast as enumerating your assets or collections, but it's something at least.
I prefer not to CIImage solution, but to ImageIO solution:
func imageAndMetadataFromImageData(data: NSData)-> (UIImage?,[String: Any]?) { let options = [kCGImageSourceShouldCache as String: kCFBooleanFalse] if let imgSrc = CGImageSourceCreateWithData(data, options as CFDictionary) { let metadata = CGImageSourceCopyPropertiesAtIndex(imgSrc, 0, options as CFDictionary) as! [String: Any] //print(metadata) // let image = UIImage(cgImage: imgSrc as! CGImage) let image = UIImage(data: data as Data) return (image, metadata) } return (nil, nil)}
below is code to get data from PHAseet
func getImageAndMeta(asset: PHAsset){ let options = PHImageRequestOptions() options.isSynchronous = true options.resizeMode = .none options.isNetworkAccessAllowed = false options.version = .current var image: UIImage? = nil var meta:[String:Any]? = nil _ = PHCachingImageManager().requestImageData(for: asset, options: options) { (imageData, dataUTI, orientation, info) in if let data = imageData { (image, meta) = imageAndMetadataFromImageData(data: data as NSData) //image = UIImage(data: data) } } // here to return image and meta}