UIImagePickerController并从现有照片中提取EXIF数据

tom*_*lor 56 iphone gps cocoa-touch exif uiimagepickercontroller

众所周知,UIImagePickerController在选择后不会返回照片的元数据.但是,应用程序商店中的一些应用程序(Mobile Fotos,PixelPipe)似乎能够读取原始文件和存储在其中的EXIF数据,使应用程序能够从所选照片中提取地理数据.

他们似乎是通过从/ private/var/mobile/Media/DCIM/100APPLE /文件夹中读取原始文件并通过EXIF库运行它来完成此操作.

但是,我无法找到一种方法来匹配从UIImagePickerController返回的照片到磁盘上的文件.我已经探索了文件大小,但原始文件是JPEG,而返回的图像是原始UIImage,因此无法知道所选图像的文件大小.

我正在考虑制作一个哈希表并匹配每个图像的前x个像素.虽然这看起来有点过头了,但可能很慢.

有什么建议?

yon*_*nel 29

你看过这个exif iPhone库吗?

http://code.google.com/p/iphone-exif/

要试试我的一面.我想从UIImagePickerController拍摄的照片中获取GPS(地理标记)坐标:/

经过深入研究后,这个库似乎将NSData信息作为输入,UIImagePickerController在拍摄快照后返回UIImage.理论上,如果我们使用从UIkit类中选择的UIImage

NSData * UIImageJPEGRepresentation (
   UIImage *image,
   CGFloat compressionQuality
);
Run Code Online (Sandbox Code Playgroud)

然后我们可以将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]];
....
....
Run Code Online (Sandbox Code Playgroud)

检索标签定义是正常的,但所有标签值都返回nil:(

如果你想试试这个库,你需要定义一个全局变量来让它运行(如文档中所解释的那样但是哼..:/)

BOOL gLogging = FALSE;

更新2
在这里回答:iPhone - 从照片访问位置信息 UIImage没有封装元信息,因此我们陷入困境:当然,不会通过此界面提供EXIF信息.

最终更新
确定我设法让它工作,至少是对选择器返回的图片进行地理标记.
在触发UIImagePickerController之前,您可以使用CLLocationManager来检索当前的CLocation
一旦拥有它,您可以使用此方法使用exif-iPhone库从CLLocation对UIImage进行地理标记:


-(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];
}

// Helper methods for location conversion -(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; } -(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]; }

nil

  • 有人有这个库的iOS5/ARC版本吗? (3认同)

Ron*_*onC 23

这适用于iOS5(beta 4)和相机胶卷(你需要为.h中的块输入defs):

-(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];
  }
}
Run Code Online (Sandbox Code Playgroud)


War*_*shi 17

有一种方法 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
}
Run Code Online (Sandbox Code Playgroud)


Yan*_*nol 5

Apple在iOS4中添加了一个Image I/O Framework,可用于从图片中读取EXIF数据.我不知道是否UIImagePickerController返回嵌入了EXIF数据的图片.

编辑:在iOS4中,您可以通过获取UIImagePickerControllerMediaMetadata传递给UIImagePickerControllerDelegate委托的信息字典中的键值来获取EXIF数据.

  • 我试过了,位置信息不存在. (2认同)

tom*_*lor -2

执行此操作的顽皮方法是遍历 UIImagePickerViewController 的视图并在委托回调中挑选出选定的图像。

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {

  id thumbnailView = [[[[[[[[[[picker.view subviews] 
                  objectAtIndex:0] subviews]
                  objectAtIndex:0] subviews]
                objectAtIndex:0] subviews]
                objectAtIndex:0] subviews]
              objectAtIndex:0];

  NSString *fullSizePath = [[[thumbnailView selectedPhoto] fileGroup] pathForFullSizeImage];
  NSString *thumbnailPath = [[[thumbnailView selectedPhoto] fileGroup] pathForThumbnailFile];

  NSLog(@"%@ and %@", fullSizePath, thumbnailPath);

}
Run Code Online (Sandbox Code Playgroud)

这将为您提供完整尺寸图像的路径,然后您可以使用您选择的 EXIF 库打开该图像。

但是,这会调用私有 API,如果您提交此应用程序,Apple检测到这些方法名称。所以不要这样做,好吗?

  • 如果我能两次投反对票,我会的,这不仅是顽皮的,而且它可能已经在当前版本的 iOS 中被淘汰了。切勿遍历不属于您的视图的视图层次结构。 (3认同)