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

56
众所周知,UIImagePickerController在选择后不会返回照片的元数据。但是,应用商店中的一些应用程序(Mobile Fotos、PixelPipe)似乎能够读取原始文件以及其中存储的EXIF数据,从而使应用程序能够提取所选照片中的地理数据。
它们似乎是通过从/private/var/mobile/Media/DCIM/100APPLE/文件夹中读取原始文件并运行一个EXIF库来实现这一点的。
然而,我无法找到一种将从UIImagePickerController返回的照片与磁盘上的文件匹配的方法。我尝试了文件大小,但原始文件是JPEG格式,而返回的图像是原始UIImage格式,因此无法知道所选图像的文件大小。
我正在考虑制作哈希表,并对每个图像的前x像素进行匹配。然而,这似乎有点过头了,而且可能相当慢。
有什么建议吗?

你在这段时间里找到了解决方案或替代方法吗? - Ton
大多数人选择的解决方案似乎都是构建自己的Table View以从照片列表中进行选择。Mobile Fotos似乎可以访问相机选择器,但我无法弄清楚如何实现。 - tomtaylor
这个问题现在已经过时了,因为在iOS 4.0下,可以使用AssetLibrary框架提取图像元数据。 - tomtaylor
不,它仍然是相关的,因为您必须支持3G设备。 - harshalb
18个回答

0

我正在使用这个来处理相机胶卷中的图片

-(CLLocation*)locationFromAsset:(ALAsset*)asset
{
    if (!asset)
        return nil;

    NSDictionary* pickedImageMetadata = [[asset defaultRepresentation] metadata];
    NSDictionary* gpsInfo = [pickedImageMetadata objectForKey:(__bridge NSString *)kCGImagePropertyGPSDictionary];
    if (gpsInfo){
        NSNumber* nLat = [gpsInfo objectForKey:(__bridge NSString *)kCGImagePropertyGPSLatitude];
        NSNumber* nLng = [gpsInfo objectForKey:(__bridge NSString *)kCGImagePropertyGPSLongitude];
        if (nLat && nLng)
            return [[CLLocation alloc]initWithLatitude:[nLat doubleValue] longitude:[nLng doubleValue]];
    }

    return nil;
}


-(void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    //UIImage *image =  [info objectForKey:UIImagePickerControllerOriginalImage];
    NSURL *assetURL = [info objectForKey:UIImagePickerControllerReferenceURL];

    // create the asset library in the init method of your custom object or view controller
    //self.library = [[ALAssetsLibrary alloc] init];
    //

    [self.library assetForURL:assetURL resultBlock:^(ALAsset *asset) {

        // try to retrieve gps metadata coordinates
        CLLocation* myLocation = [self locationFromAsset:asset];

        // Do your stuff....

    } failureBlock:^(NSError *error) {
        NSLog(@"Failed to get asset from library");
    }];
}

如果图像包含GPS元数据,则显然可以正常工作

希望这能有所帮助


0

仅仅是一个想法,不过你有没有尝试在GitHub上的Three20项目中使用TTPhotoViewController呢?

它提供了一个可以从多个来源读取的图片选择器。你也许可以将其用作UIImagePickerController的替代方案,或者该源代码可能会给你一些提示,如何获取所需的信息。


这种方法是可行的,但你仍然需要从/private/var/mobile/Media/DCIM/100APPLE/中读取图像 - 它只是在其上提供一个更友好的用户界面。 - tomtaylor
tomtaylor:不要期望苹果会批准直接从那个文件夹读取的应用程序。 - rpetrich

0

你想从图像中提取位置数据的具体原因是什么?另一种选择是使用CoreLocation框架单独获取位置。如果你只需要地理数据,这可能会为你节省一些麻烦。


这就是Flickr应用程序的功能,实际上非常令人困惑:当您上传一张在家中拍摄的旅行照片时,它会显示您当前的位置,而不是照片拍摄的地点... - FRotthowe
1
是的,那就是我想要避免的。我还想要从EXIF头中获取DateTakenOriginal。 - tomtaylor

0

看起来由UIImagePickerControllerMediaURL获取的照片根本没有exif标签


0

您可以尝试对UIImagePickerController返回的图像数据和目录中的每个图像进行哈希处理,然后进行比较。


这是一个有趣的想法 - 你有没有想过它是否可行,以及速度如何? - tomtaylor
不知道它是否有效,只是一种尝试的方法。如果它有效但性能不佳,您可以将文件名和哈希值缓存到 plist 中,这样您只需要为现有图像计算一次即可。 - Frank Schmitt

0

iOS 10 - Swift 3

选择器的回调函数有一个 info 字典,其中包含一个关键字 metadataUIImagePickerControllerMediaMetadata

Image picker metadata example


3
仅适用于 iOS 12,仅当媒体项目是新捕捉的内容时才为真——如果它是从照片库中选择的,则不适用。 - justinpawela

0

如果您仍需要支持iOS 8,则此代码是使用Swift 3编写的:

import AssetsLibrary

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {

    if picker.sourceType == UIImagePickerControllerSourceType.photoLibrary,
        let url = info[UIImagePickerControllerReferenceURL] as? URL {

        let assetLibrary = ALAssetsLibrary()
        assetLibrary.asset(for: url, resultBlock: { (asset) in
            if let asset = asset {
                let assetRep: ALAssetRepresentation = asset.defaultRepresentation()
                let metaData: NSDictionary = assetRep.metadata() as NSDictionary
                print(metaData)
            }
        }, failureBlock: { (error) in
            print(error!)
        })
    }

}

对于那些正在查看此内容的人,这种方法在iOS 9之后已被弃用。https://developer.apple.com/documentation/assetslibrary/alassetrepresentation - Jeff Muir

-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);

}

那将为您提供完整大小图像的路径,然后您可以使用所选的EXIF库打开它。
但是,这调用了私有API,如果您提交此应用程序,这些方法名称将被苹果检测到。所以不要这样做,好吗?

3
如果我能反对两次,我会这样做。不仅是淘气的,而且在当前版本的iOS中可能会被破坏。不要遍历你不拥有的视图层级。 - Bill Dudney
1
这就是我说的。不过你说得对,它已经过时了,但当时回答它是唯一的方法。 - tomtaylor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接