它们似乎是通过从/private/var/mobile/Media/DCIM/100APPLE/文件夹中读取原始文件并运行一个EXIF库来实现这一点的。
然而,我无法找到一种将从UIImagePickerController返回的照片与磁盘上的文件匹配的方法。我尝试了文件大小,但原始文件是JPEG格式,而返回的图像是原始UIImage格式,因此无法知道所选图像的文件大小。
我正在考虑制作哈希表,并对每个图像的前x像素进行匹配。然而,这似乎有点过头了,而且可能相当慢。
有什么建议吗?
NSData * UIImageJPEGRepresentation (
UIImage *image,
CGFloat compressionQuality
);
接下来,我们可以将UIImage转换为NSData实例,然后与iPhone exif库一起使用。
更新:
我对上面提到的库进行了测试,似乎它可以正常工作。但是由于我对EXIF格式的知识有限,以及库中缺乏高级API,我无法获取EXIF标签的值。
以下是我的代码,如果您能进一步帮助,请参考:
#import "EXFJpeg.h"
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo {
NSLog(@"image picked %@ with info %@", image, editingInfo);
NSData* jpegData = UIImageJPEGRepresentation (image,0.5);
EXFJpeg* jpegScanner = [[EXFJpeg alloc] init];
[jpegScanner scanImageData: jpegData];
EXFMetaData* exifData = jpegScanner.exifMetaData;
EXFJFIF* jfif = jpegScanner.jfif;
EXFTag* tagDefinition = [exifData tagDefinition: [NSNumber numberWithInt:EXIF_DateTime]];
//EXFTag* latitudeDef = [exifData tagDefinition: [NSNumber numberWithInt:EXIF_GPSLatitude]];
//EXFTag* longitudeDef = [exifData tagDefinition: [NSNumber numberWithInt:EXIF_GPSLongitude]];
id latitudeValue = [exifData tagValue:[NSNumber numberWithInt:EXIF_GPSLatitude]];
id longitudeValue = [exifData tagValue:[NSNumber numberWithInt:EXIF_GPSLongitude]];
id datetime = [exifData tagValue:[NSNumber numberWithInt:EXIF_DateTime]];
id t = [exifData tagValue:[NSNumber numberWithInt:EXIF_Model]];
....
....
nil
:(BOOL gLogging = FALSE;
更新2FINAL UPDATE
Ok I managed to get it working, at least to geotag properly pictures returned by the picker.
Before triggering the UIImagePickerController, it's up to you to use the CLLocationManager to retrieve the current CLocation
Once you have it, you can use this method that uses exif-iPhone library to geotag the UIImage from the CLLocation :
-(NSData*) geotagImage:(UIImage*)image withLocation:(CLLocation*)imageLocation {
NSData* jpegData = UIImageJPEGRepresentation(image, 0.8);
EXFJpeg* jpegScanner = [[EXFJpeg alloc] init];
[jpegScanner scanImageData: jpegData];
EXFMetaData* exifMetaData = jpegScanner.exifMetaData;
// end of helper methods
// adding GPS data to the Exif object
NSMutableArray* locArray = [self createLocArray:imageLocation.coordinate.latitude];
EXFGPSLoc* gpsLoc = [[EXFGPSLoc alloc] init];
[self populateGPS: gpsLoc :locArray];
[exifMetaData addTagValue:gpsLoc forKey:[NSNumber numberWithInt:EXIF_GPSLatitude] ];
[gpsLoc release];
[locArray release];
locArray = [self createLocArray:imageLocation.coordinate.longitude];
gpsLoc = [[EXFGPSLoc alloc] init];
[self populateGPS: gpsLoc :locArray];
[exifMetaData addTagValue:gpsLoc forKey:[NSNumber numberWithInt:EXIF_GPSLongitude] ];
[gpsLoc release];
[locArray release];
NSString* ref;
if (imageLocation.coordinate.latitude <0.0)
ref = @"S";
else
ref =@"N";
[exifMetaData addTagValue: ref forKey:[NSNumber numberWithInt:EXIF_GPSLatitudeRef] ];
if (imageLocation.coordinate.longitude <0.0)
ref = @"W";
else
ref =@"E";
[exifMetaData addTagValue: ref forKey:[NSNumber numberWithInt:EXIF_GPSLongitudeRef] ];
NSMutableData* taggedJpegData = [[NSMutableData alloc] init];
[jpegScanner populateImageData:taggedJpegData];
[jpegScanner release];
return [taggedJpegData autorelease];
}
// 位置转换的辅助方法 -(NSMutableArray*) createLocArray:(double) val{ val = fabs(val); NSMutableArray* array = [[NSMutableArray alloc] init]; double deg = (int)val; [array addObject:[NSNumber numberWithDouble:deg]]; val = val - deg; val = val*60; double minutes = (int) val; [array addObject:[NSNumber numberWithDouble:minutes]]; val = val - minutes; val = val*60; double seconds = val; [array addObject:[NSNumber numberWithDouble:seconds]]; return array; } // 将GPS地理位置信息填充到EXFGPSLoc对象中 -(void) populateGPS:(EXFGPSLoc* ) gpsLoc :(NSArray*) locArray{ long numDenumArray[2]; long* arrPtr = numDenumArray; // 将度数转化为分数形式 [EXFUtils convertRationalToFraction:&arrPtr :[locArray objectAtIndex:0]]; EXFraction* fract = [[EXFraction alloc] initWith:numDenumArray[0]:numDenumArray[1]]; gpsLoc.degrees = fract; [fract release]; // 将分钟数转化为分数形式 [EXFUtils convertRationalToFraction:&arrPtr :[locArray objectAtIndex:1]]; fract = [[EXFraction alloc] initWith:numDenumArray[0] :numDenumArray[1]]; gpsLoc.minutes = fract; [fract release]; // 将秒数转化为分数形式 [EXFUtils convertRationalToFraction:&arrPtr :[locArray objectAtIndex:2]]; fract = [[EXFraction alloc] initWith:numDenumArray[0] :numDenumArray[1]]; gpsLoc.seconds = fract; [fract release]; }
这适用于iOS5(beta 4)和相机翻转(您需要在.h文件中为块类型定义):
-(void) imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
if ([mediaType isEqualToString:(NSString*)kUTTypeImage]) {
NSURL *url = [info objectForKey:UIImagePickerControllerReferenceURL];
if (url) {
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset) {
CLLocation *location = [myasset valueForProperty:ALAssetPropertyLocation];
// location contains lat/long, timestamp, etc
// extracting the image is more tricky and 5.x beta ALAssetRepresentation has bugs!
};
ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *myerror) {
NSLog(@"cant get image - %@", [myerror localizedDescription]);
};
ALAssetsLibrary *assetsLib = [[ALAssetsLibrary alloc] init];
[assetsLib assetForURL:url resultBlock:resultblock failureBlock:failureblock];
}
}
iOS 8
中有一种方法
不使用任何第三方EXIF
库。
#import <Photos/Photos.h>
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSURL *url = [info objectForKey:UIImagePickerControllerReferenceURL];
PHFetchResult *fetchResult = [PHAsset fetchAssetsWithALAssetURLs:@[url] options:nil];
PHAsset *asset = fetchResult.firstObject;
//All you need is
//asset.location.coordinate.latitude
//asset.location.coordinate.longitude
//Other useful properties of PHAsset
//asset.favorite
//asset.modificationDate
//asset.creationDate
}
苹果在iOS4中添加了一个Image I/O框架,可用于从图片中读取EXIF数据。但我不知道UIImagePickerController是否返回带有嵌入式EXIF数据的图片。
编辑:在iOS4中,您可以通过获取传递给UIImagePickerControllerDelegate委托的信息字典中UIImagePickerControllerMediaMetadata键的值来获取EXIF数据。
UIImagePickerControllerMediaMetadata
这样的键。它是 nil
。 - Can Poyrazoğlu我有一个类似的问题,我只想知道一张照片拍摄的日期,但上面提到的方法都不能简单地解决我的问题(例如没有外部库),所以这里是我能找到的所有数据,你可以在使用选择器选中图片后从中提取:
// Inside whatever implements UIImagePickerControllerDelegate
@import AssetsLibrary;
// ... your other code here ...
@implementation MYImagePickerDelegate
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSString *mediaType = info[UIImagePickerControllerMediaType];
UIImage *originalImage = info[UIImagePickerControllerOriginalImage];
UIImage *editedImage = info[UIImagePickerControllerEditedImage];
NSValue *cropRect = info[UIImagePickerControllerCropRect];
NSURL *mediaUrl = info[UIImagePickerControllerMediaURL];
NSURL *referenceUrl = info[UIImagePickerControllerReferenceURL];
NSDictionary *mediaMetadata = info[UIImagePickerControllerMediaMetadata];
NSLog(@"mediaType=%@", mediaType);
NSLog(@"originalImage=%@", originalImage);
NSLog(@"editedImage=%@", editedImage);
NSLog(@"cropRect=%@", cropRect);
NSLog(@"mediaUrl=%@", mediaUrl);
NSLog(@"referenceUrl=%@", referenceUrl);
NSLog(@"mediaMetadata=%@", mediaMetadata);
if (!referenceUrl) {
NSLog(@"Media did not have reference URL.");
} else {
ALAssetsLibrary *assetsLib = [[ALAssetsLibrary alloc] init];
[assetsLib assetForURL:referenceUrl
resultBlock:^(ALAsset *asset) {
NSString *type =
[asset valueForProperty:ALAssetPropertyType];
CLLocation *location =
[asset valueForProperty:ALAssetPropertyLocation];
NSNumber *duration =
[asset valueForProperty:ALAssetPropertyDuration];
NSNumber *orientation =
[asset valueForProperty:ALAssetPropertyOrientation];
NSDate *date =
[asset valueForProperty:ALAssetPropertyDate];
NSArray *representations =
[asset valueForProperty:ALAssetPropertyRepresentations];
NSDictionary *urls =
[asset valueForProperty:ALAssetPropertyURLs];
NSURL *assetUrl =
[asset valueForProperty:ALAssetPropertyAssetURL];
NSLog(@"type=%@", type);
NSLog(@"location=%@", location);
NSLog(@"duration=%@", duration);
NSLog(@"assetUrl=%@", assetUrl);
NSLog(@"orientation=%@", orientation);
NSLog(@"date=%@", date);
NSLog(@"representations=%@", representations);
NSLog(@"urls=%@", urls);
}
failureBlock:^(NSError *error) {
NSLog(@"Failed to get asset: %@", error);
}];
}
[picker dismissViewControllerAnimated:YES
completion:nil];
}
@end
mediaType=public.image
originalImage=<UIImage: 0x7fb38e00e870> size {1280, 850} orientation 0 scale 1.000000
editedImage=<UIImage: 0x7fb38e09e1e0> size {640, 424} orientation 0 scale 1.000000
cropRect=NSRect: {{0, 0}, {1280, 848}}
mediaUrl=(null)
referenceUrl=assets-library://asset/asset.JPG?id=AC072879-DA36-4A56-8A04-4D467C878877&ext=JPG
mediaMetadata=(null)
type=ALAssetTypePhoto
location=(null)
duration=ALErrorInvalidProperty
assetUrl=assets-library://asset/asset.JPG?id=AC072879-DA36-4A56-8A04-4D467C878877&ext=JPG
orientation=0
date=2014-07-14 04:28:18 +0000
representations=(
"public.jpeg"
)
urls={
"public.jpeg" = "assets-library://asset/asset.JPG?id=AC072879-DA36-4A56-8A04-4D467C878877&ext=JPG";
}
对于 iOS 8 及更高版本,您可以使用Photos Framework。
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let url = info[UIImagePickerControllerReferenceURL] as? URL
if url != nil {
let fetchResult = PHAsset.fetchAssets(withALAssetURLs: [url!], options: nil)
let asset = fetchResult.firstObject
print(asset?.location?.coordinate.latitude)
print(asset?.creationDate)
}
}
使用UIImagePickerControllerMediaURL
字典键获取原始文件的文件URL。尽管文档中所说,您可以获取照片的文件URL而不仅仅是电影。
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
// Try to get the original file.
NSURL *originalFile = [info objectForKey:UIImagePickerControllerMediaURL];
if (originalFile) {
NSData *fileData = [NSData dataWithContentsOfURL:originalFile];
}
}
这是公共API没有提供的内容,但对许多人可能很有用。您的主要途径是向苹果提交错误报告,描述您需要什么(解释一下为什么需要也可能有帮助)。希望您的请求能够在未来的版本中得到满足。
提交错误报告后,您还可以使用iPhone开发者计划成员附带的开发技术支持(DTS)事件之一。如果有公共方法可以实现此功能,苹果工程师会知道。否则,它至少可以帮助您的困境在总部获得更多关注。祝您好运!
- (BOOL)writeCGImageToCameraRoll:(CGImageRef)cgImage withMetadata:(NSDictionary *)metadata
{
NSDictionary *Exif = [metadata objectForKey:@"Exif"]; // Add this line
}