从UIImage获取Exif数据 – UIImagePickerController
如何从UIImagePickerController中selectUIImage的Exif信息?
我为此做了很多的研发工作,得到了很多答复,但是仍然没有实现。
我已经通过这个和这个链接
请帮我解决这个问题。
提前致谢..
有趣的问题! 我想出了以下的解决scheme工作从您的照片库中选取的图像(注意我的代码使用ARC ):
导入AssetsLibrary.framework
和ImageIO.framework
。
然后在你的.h文件中包含所需的类:
#import <AssetsLibrary/ALAsset.h> #import <AssetsLibrary/ALAssetRepresentation.h> #import <ImageIO/CGImageSource.h> #import <ImageIO/CGImageProperties.h>
把这个放在你的imagePickerController:didFinishPickingMediaWithInfo:
里面imagePickerController:didFinishPickingMediaWithInfo:
delegate方法:
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; [library assetForURL:[info objectForKey:UIImagePickerControllerReferenceURL] resultBlock:^(ALAsset *asset) { ALAssetRepresentation *image_representation = [asset defaultRepresentation]; // create a buffer to hold image data uint8_t *buffer = (Byte*)malloc(image_representation.size); NSUInteger length = [image_representation getBytes:buffer fromOffset: 0.0 length:image_representation.size error:nil]; if (length != 0) { // buffer -> NSData object; free buffer afterwards NSData *adata = [[NSData alloc] initWithBytesNoCopy:buffer length:image_representation.size freeWhenDone:YES]; // identify image type (jpeg, png, RAW file, ...) using UTI hint NSDictionary* sourceOptionsDict = [NSDictionary dictionaryWithObjectsAndKeys:(id)[image_representation UTI] ,kCGImageSourceTypeIdentifierHint,nil]; // create CGImageSource with NSData CGImageSourceRef sourceRef = CGImageSourceCreateWithData((__bridge CFDataRef) adata, (__bridge CFDictionaryRef) sourceOptionsDict); // get imagePropertiesDictionary CFDictionaryRef imagePropertiesDictionary; imagePropertiesDictionary = CGImageSourceCopyPropertiesAtIndex(sourceRef,0, NULL); // get exif data CFDictionaryRef exif = (CFDictionaryRef)CFDictionaryGetValue(imagePropertiesDictionary, kCGImagePropertyExifDictionary); NSDictionary *exif_dict = (__bridge NSDictionary*)exif; NSLog(@"exif_dict: %@",exif_dict); // save image WITH meta data NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; NSURL *fileURL = nil; CGImageRef imageRef = CGImageSourceCreateImageAtIndex(sourceRef, 0, imagePropertiesDictionary); if (![[sourceOptionsDict objectForKey:@"kCGImageSourceTypeIdentifierHint"] isEqualToString:@"public.tiff"]) { fileURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@.%@", documentsDirectory, @"myimage", [[[sourceOptionsDict objectForKey:@"kCGImageSourceTypeIdentifierHint"] componentsSeparatedByString:@"."] objectAtIndex:1] ]]; CGImageDestinationRef dr = CGImageDestinationCreateWithURL ((__bridge CFURLRef)fileURL, (__bridge CFStringRef)[sourceOptionsDict objectForKey:@"kCGImageSourceTypeIdentifierHint"], 1, NULL ); CGImageDestinationAddImage(dr, imageRef, imagePropertiesDictionary); CGImageDestinationFinalize(dr); CFRelease(dr); } else { NSLog(@"no valid kCGImageSourceTypeIdentifierHint found …"); } // clean up CFRelease(imageRef); CFRelease(imagePropertiesDictionary); CFRelease(sourceRef); } else { NSLog(@"image_representation buffer length == 0"); } } failureBlock:^(NSError *error) { NSLog(@"couldn't get asset: %@", error); } ];
我注意到的一件事是,iOS会要求用户允许定位服务 – 如果他否认,你将无法得到图像数据…
编辑
添加了代码来保存图像,包括其元数据。 这是一个快速的方法,所以也许有更好的方法,但它的工作原理!
这些答案似乎都非常复杂。 如果图像已经保存到相机胶卷,并且您有ALAsset(来自UIImagePicker或ALAssetLibrary),您可以像这样获取元数据:
asset.defaultRepresentation.metadata;
如果你想从相机胶卷保存该图像到另一个位置(比如沙盒/文档),只需要:
CGImageDestinationRef imageDestinationRef = CGImageDestinationCreateWithURL((__bridge CFURLRef)urlToSaveTo, kUTTypeJPEG, 1, NULL); CFDictionaryRef imagePropertiesRef = (__bridge CFDictionaryRef)asset.defaultRepresentation.metadata; CGImageDestinationAddImage(imageDestinationRef, asset.defaultRepresentation.fullResolutionImage, imagePropertiesRef); if (!CGImageDestinationFinalize(imageDestinationRef)) NSLog(@"Failed to copy photo on save to %@", urlToSaveTo); CFRelease(imageDestinationRef);
我find了解决办法,并从这里得到答案
从这里我们可以得到GPS信息。
非常感谢所有帮助我解决这个问题。
UPDATE
这是我自己创build的另一个function,也返回Exif数据以及GPS数据,在这个function我们不需要任何第三方库..但你必须打开位置服务。 并使用当前的经度和纬度。 所以不得不使用CoreLocation.framework
//FOR CAMERA IMAGE -(NSMutableData *)getImageWithMetaData:(UIImage *)pImage { NSData* pngData = UIImagePNGRepresentation(pImage); CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)pngData, NULL); NSDictionary *metadata = (NSDictionary *) CGImageSourceCopyPropertiesAtIndex(source, 0, NULL); NSMutableDictionary *metadataAsMutable = [[metadata mutableCopy]autorelease]; [metadata release]; //For GPS Dictionary NSMutableDictionary *GPSDictionary = [[[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyGPSDictionary]mutableCopy]autorelease]; if(!GPSDictionary) GPSDictionary = [NSMutableDictionary dictionary]; [GPSDictionary setValue:[NSNumber numberWithDouble:currentLatitude] forKey:(NSString*)kCGImagePropertyGPSLatitude]; [GPSDictionary setValue:[NSNumber numberWithDouble:currentLongitude] forKey:(NSString*)kCGImagePropertyGPSLongitude]; NSString* ref; if (currentLatitude <0.0) ref = @"S"; else ref =@"N"; [GPSDictionary setValue:ref forKey:(NSString*)kCGImagePropertyGPSLatitudeRef]; if (currentLongitude <0.0) ref = @"W"; else ref =@"E"; [GPSDictionary setValue:ref forKey:(NSString*)kCGImagePropertyGPSLongitudeRef]; [GPSDictionary setValue:[NSNumber numberWithFloat:location.altitude] forKey:(NSString*)kCGImagePropertyGPSAltitude]; //For EXIF Dictionary NSMutableDictionary *EXIFDictionary = [[[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyExifDictionary]mutableCopy]autorelease]; if(!EXIFDictionary) EXIFDictionary = [NSMutableDictionary dictionary]; [EXIFDictionary setObject:[NSDate date] forKey:(NSString*)kCGImagePropertyExifDateTimeOriginal]; [EXIFDictionary setObject:[NSDate date] forKey:(NSString*)kCGImagePropertyExifDateTimeDigitized]; //add our modified EXIF data back into the image's metadata [metadataAsMutable setObject:EXIFDictionary forKey:(NSString *)kCGImagePropertyExifDictionary]; [metadataAsMutable setObject:GPSDictionary forKey:(NSString *)kCGImagePropertyGPSDictionary]; CFStringRef UTI = CGImageSourceGetType(source); NSMutableData *dest_data = [NSMutableData data]; CGImageDestinationRef destination = CGImageDestinationCreateWithData((CFMutableDataRef)dest_data, UTI, 1, NULL); if(!destination) dest_data = [[pngData mutableCopy] autorelease]; else { CGImageDestinationAddImageFromSource(destination, source, 0, (CFDictionaryRef) metadataAsMutable); BOOL success = CGImageDestinationFinalize(destination); if(!success) dest_data = [[pngData mutableCopy] autorelease]; } if(destination) CFRelease(destination); CFRelease(source); return dest_data; } //FOR PHOTO LIBRARY IMAGE -(NSMutableData *)getImagedataPhotoLibrary:(NSDictionary *)pImgDictionary andImage:(UIImage *)pImage { NSData* data = UIImagePNGRepresentation(pImage); CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)data, NULL); NSMutableDictionary *metadataAsMutable = [[pImgDictionary mutableCopy]autorelease]; CFStringRef UTI = CGImageSourceGetType(source); NSMutableData *dest_data = [NSMutableData data]; //For Mutabledata CGImageDestinationRef destination = CGImageDestinationCreateWithData((CFMutableDataRef)dest_data, UTI, 1, NULL); if(!destination) dest_data = [[data mutableCopy] autorelease]; else { CGImageDestinationAddImageFromSource(destination, source, 0, (CFDictionaryRef) metadataAsMutable); BOOL success = CGImageDestinationFinalize(destination); if(!success) dest_data = [[data mutableCopy] autorelease]; } if(destination) CFRelease(destination); CFRelease(source); return dest_data; }
我们将检索这样的数据
//FOR CAMERA IMAGE NSData *originalImgData = [self getImageWithMetaData:imgOriginal]; //FOR PHOTO LIBRARY IMAGE [self getImagedataPhotoLibrary:[[myasset defaultRepresentation] metadata] andImage:imgOriginal];
对于所有这些,你应该必须导入AssetsLibrary.framework
和ImageIO.framework
。
我用这个方法从图像中获取exifdata字典,我希望这也适用于你
-(void)getExifDataFromImage:(UIImage *)currentImage { NSData* pngData = UIImageJPEGRepresentation(currentImage, 1.0); CGImageSourceRef mySourceRef = CGImageSourceCreateWithData((CFDataRef)pngData, NULL); //CGImageSourceRef mySourceRef = CGImageSourceCreateWithURL((__bridge CFURLRef)myURL, NULL); if (mySourceRef != NULL) { NSDictionary *myMetadata = (__bridge NSDictionary *)CGImageSourceCopyPropertiesAtIndex(mySourceRef,0,NULL); NSDictionary *exifDic = [myMetadata objectForKey:(NSString *)kCGImagePropertyExifDictionary]; NSDictionary *tiffDic = [myMetadata objectForKey:(NSString *)kCGImagePropertyTIFFDictionary]; NSLog(@"exifDic properties: %@", myMetadata); //all data float rawShutterSpeed = [[exifDic objectForKey:(NSString *)kCGImagePropertyExifExposureTime] floatValue]; int decShutterSpeed = (1 / rawShutterSpeed); NSLog(@"Camera %@",[tiffDic objectForKey:(NSString *)kCGImagePropertyTIFFModel]); NSLog(@"Focal Length %@mm",[exifDic objectForKey:(NSString *)kCGImagePropertyExifFocalLength]); NSLog(@"Shutter Speed %@", [NSString stringWithFormat:@"1/%d", decShutterSpeed]); NSLog(@"Aperture f/%@",[exifDic objectForKey:(NSString *)kCGImagePropertyExifFNumber]); NSNumber *ExifISOSpeed = [[exifDic objectForKey:(NSString*)kCGImagePropertyExifISOSpeedRatings] objectAtIndex:0]; NSLog(@"ISO %ld",[ExifISOSpeed integerValue]); NSLog(@"Taken %@",[exifDic objectForKey:(NSString*)kCGImagePropertyExifDateTimeDigitized]); } }
您需要ALAssetsLibrary才能从图像中实际检索EXIF信息。 只有将EXIF保存到照片库时,EXIF才会添加到图像中。 即使使用ALAssetLibrary从库中获取图像资源,如果将其设置为UIImage,也将丢失所有EXIF信息。
我已经试图将GPS坐标插入到由iPad相机采集的图像元数据中,正如Mehul所build议的那样。 它工作,感谢您的post。
PS谁打算使用该代码,只是取代函数顶部的两个地理位置 – (NSMutableData *)getImageWithMetaData:(UIImage *)pImage {
double currentLatitude = [locationManager location].coordinate.latitude; double currentLongitude = [locationManager location].coordinate.longitude;
…
通过假设你已经在代码中的某处locationManager初始化了,如下所示:
locationManager = [[CLLocationManager alloc] init]; [locationManager setDesiredAccuracy:kCLLocationAccuracyBest]; [locationManager setDelegate:self]; // Not necessary in this case [locationManager startUpdatingLocation]; // Not neccessary in this case
并通过导入CoreLocation / CoreLocation.h和ImageIO / ImageIO.h头文件与相关的框架。