ios 从iOS iphone相机返回的图像中读取GPS数据

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10302250/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 18:02:48  来源:igfitidea点击:

Reading the GPS data from the image returned by the camera in iOS iphone

iosgeolocationgpscamera

提问by Paul Cezanne

I need to get the GPS coordinates of an image taken with the iOS device's camera. I do not care about the Camera Roll images, just the image taken with UIImagePickerControllerSourceTypeCamera.

我需要获取使用 iOS 设备的相机拍摄的图像的 GPS 坐标。我不关心相机胶卷图像,只关心使用 UIImagePickerControllerSourceTypeCamera 拍摄的图像。

I've read many stackoverflow answers, like Get Exif data from UIImage - UIImagePickerController, which either assumes you are using the AssetsLibrary framework, which doesn't seem to work on camera images, or use CoreLocaiton to get the latitude/longitude from the app itself, not from the image.

我已经阅读了许多 stackoverflow 的答案,例如从 UIImage 获取 Exif 数据 - UIImagePickerController,它要么假设您使用的是 AssetsLibrary 框架,该框架似乎不适用于相机图像,要么使用 CoreLocaiton 从应用程序获取纬度/经度本身,而不是来自图像。

Using CoreLocation is not an option. That will not give me the coordinates when the shutter button was pressed. (With the CoreLocation based solutions, you either need to record the coords before you bring up the camera view or after, and of course if the device is moving the coordinates will be wrong. This method should work with a stationary device.)

使用 CoreLocation不是一个选项。当按下快门按钮时,这不会给我坐标。(使用基于 CoreLocation 的解决方案,您需要在调出相机视图之前或之后记录坐标,当然如果设备正在移动坐标将是错误的。这种方法应该适用于固定设备。)

I am iOS5 only, so I don't need to support older devices. This is also for a commercial product so I cannot use http://code.google.com/p/iphone-exif/.

我只是 iOS5,所以我不需要支持旧设备。这也适用于商业产品,因此我无法使用http://code.google.com/p/iphone-exif/

So, what are my options for reading the GPS data from the image returned by the camera in iOS5? All I can think of right now is to save the image to Camera Roll and then use the AssetsLibrary, but that seems hokey.

那么,从iOS5中相机返回的图像中读取GPS数据有哪些选择?我现在能想到的就是将图像保存到相机胶卷,然后使用 AssetsLibrary,但这似乎很糟糕。

Thanks!

谢谢!



Here's the code I wrote based on Caleb's answer.

这是我根据 Caleb 的回答编写的代码。

    UIImage *image =  [info objectForKey:UIImagePickerControllerOriginalImage];

    NSData *jpeg = UIImageJPEGRepresentation(image,1.0);
    CGImageSourceRef  source ;
    source = CGImageSourceCreateWithData((__bridge CFDataRef)jpeg, NULL);

    NSDictionary *metadataNew = (__bridge NSDictionary *) CGImageSourceCopyPropertiesAtIndex(source,0,NULL);  

    NSLog(@"%@",metadataNew);

and my Console shows:

我的控制台显示:

    2012-04-26 14:15:37:137 ferret[2060:1799] {
        ColorModel = RGB;
        Depth = 8;
        Orientation = 6;
        PixelHeight = 1936;
        PixelWidth = 2592;
        "{Exif}" =     {
            ColorSpace = 1;
            PixelXDimension = 2592;
            PixelYDimension = 1936;
        };
        "{JFIF}" =     {
            DensityUnit = 0;
            JFIFVersion =         (
                1,
                1
            );
            XDensity = 1;
            YDensity = 1;
        };
        "{TIFF}" =     {
            Orientation = 6;
        };
    }

No latitude/longitude.

没有纬度/经度。

采纳答案by Paul Cezanne

One possibility is to leaving CoreLocation running when the camera is visible. Record each CCLocation into an array along with the time of the sample. When the photo comes back, find its time, then match the closest CClocation from the array.

一种可能性是在相机可见时让 CoreLocation 保持运行。将每个 CLocation 与样本时间一起记录到一个数组中。当照片回来时,找到它的时间,然后匹配数组中最近的 CClocation。

Sounds kludgy but it will work.

听起来很笨拙,但它会起作用。

回答by Carlos Borges

The problem is that since iOS 4 UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];strips the geolocation out. To solve this problem you have to use the original photo path to get access to the full image metadata. With something like this:

问题是因为 iOS 4UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];去掉了地理定位。要解决此问题,您必须使用原始照片路径来访问完整的图像元数据。像这样:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
    NSURL *referenceURL = [info objectForKey:UIImagePickerControllerReferenceURL];
    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
    [library assetForURL:referenceURL resultBlock:^(ALAsset *asset) {
        ALAssetRepresentation *rep = [asset defaultRepresentation];
        NSDictionary *metadata = rep.metadata;
        NSLog(@"%@", metadata);

        CGImageRef iref = [rep fullScreenImage] ;

        if (iref) {
            self.imageView.image = [UIImage imageWithCGImage:iref];
        }
    } failureBlock:^(NSError *error) {
        // error handling
    }];

The output should be something like:

输出应该是这样的:

{
    ColorModel = RGB;
    DPIHeight = 72;
    DPIWidth = 72;
    Depth = 8;
    Orientation = 6;
    PixelHeight = 1936;
    PixelWidth = 2592;
    "{Exif}" =     {
        ApertureValue = "2.970854";
        BrightnessValue = "1.115874";
        ColorSpace = 1;
        ComponentsConfiguration =         (
            0,
            0,
            0,
            1
        );
        DateTimeDigitized = "2012:07:14 21:55:05";
        DateTimeOriginal = "2012:07:14 21:55:05";
        ExifVersion =         (
            2,
            2,
            1
        );
        ExposureMode = 0;
        ExposureProgram = 2;
        ExposureTime = "0.06666667";
        FNumber = "2.8";
        Flash = 24;
        FlashPixVersion =         (
            1,
            0
        );
        FocalLength = "3.85";
        ISOSpeedRatings =         (
            200
        );
        MeteringMode = 5;
        PixelXDimension = 2592;
        PixelYDimension = 1936;
        SceneCaptureType = 0;
        SensingMethod = 2;
        Sharpness = 2;
        ShutterSpeedValue = "3.9112";
        SubjectArea =         (
            1295,
            967,
            699,
            696
        );
        WhiteBalance = 0;
    };
    "{GPS}" =     {
        Altitude = "1167.528";
        AltitudeRef = 0;
        ImgDirection = "278.8303";
        ImgDirectionRef = T;
        Latitude = "15.8235";
        LatitudeRef = S;
        Longitude = "47.99416666666666";
        LongitudeRef = W;
        TimeStamp = "00:55:04.59";
    };
    "{TIFF}" =     {
        DateTime = "2012:07:14 21:55:05";
        Make = Apple;
        Model = "iPhone 4";
        Orientation = 6;
        ResolutionUnit = 2;
        Software = "5.1.1";
        XResolution = 72;
        YResolution = 72;
        "_YCbCrPositioning" = 1;
    };
}

回答by Chris Markle

We have worked a lot with the camera and UIImagePickerControllerand, at least up to and including iOS 5.1.1, it does not return location data in the metadata for either photos or videos shot with UIImagePickerController.

我们在相机方面做了很多工作UIImagePickerController,至少在 iOS 5.1.1 之前,它不会在元数据中返回使用UIImagePickerController.

It doesn't matter whether location services is enabled for the Camera app or not; this controls the Camera app's use of location services, not the camera function within UIImagePickerController.

相机应用程序是否启用位置服务并不重要;这控制了相机应用程序对位置服务的使用,而不是UIImagePickerController.

Your app will need to use the CLLocationclass to get the location and then add it to the image or video returned from the camera. Whether your app can get the location will depend on whether the user authorizes access to location services for your app. And note that the user can disable location services for you app (or entirely for the device) at any time via Settings > LocationServices.

您的应用程序将需要使用CLLocation该类来获取位置,然后将其添加到从相机返回的图像或视频中。您的应用能否获取位置取决于用户是否授权访问您的应用的位置服务。请注意,用户可以随时通过Settings > Location服务为您的应用程序(或完全为设备)禁用位置服务。

回答by Jim

You're not using the image data from the camera in the code you've posted, you've generated a JPEG representation of it, which would essentially discard all the metadata. Use image.CGImagelike Caleb suggested.

您没有在发布的代码中使用来自相机的图像数据,而是生成了它的 JPEG 表示,这基本上会丢弃所有元数据。image.CGImage像 Caleb 建议的那样使用。

Also:

还:

This is also for a commercial product so I cannot use http://code.google.com/p/iphone-exif/.

这也适用于商业产品,因此我无法使用http://code.google.com/p/iphone-exif/

The author quite clearly states that commercial licensing is available.

作者非常清楚地说明了商业许可是可用的。

回答by Caleb

Can't say I've needed to do exactly this in my own stuff, but from the docs it seems pretty clear that if you're using UIImagePickerControlleryou can get the image that the user just took from the -imagePicker:didFinishPickingMediaWithInfo:delegate method. Use the key UIImagePickerControllerOriginalImageto get the image.

不能说我需要在我自己的东西中完全做到这一点,但是从文档中很明显,如果您正在使用,UIImagePickerController您可以获得用户刚刚从-imagePicker:didFinishPickingMediaWithInfo:委托方法中获取的图像。使用密钥UIImagePickerControllerOriginalImage来获得图像。

Once you've got the image, you should be able to access its properties, including EXIF data, as described in QA1654 Accessing image properties with ImageIO. To create the CGImageSource, I'd look at CGImageSourceCreateWithData()and use the data that you get from the UIImage's CGImagemethod. Once you've got the image source, you can access the various attributes via CGImageSourceCopyProperties().

获得图像后,您应该能够访问其属性,包括 EXIF 数据,如QA1654 使用 ImageIO 访问图像属性中所述。要创建 CGImageSource,我会查看CGImageSourceCreateWithData()并使用您从 UIImage 的CGImage方法中获得的数据。获得图像源后,您可以通过CGImageSourceCopyProperties().

回答by Guilherme Torres Castro

As point out by Chris Markle, Apple does strip out GPS data from EXIF. But you can open the RAW data of the image, and parse the data yourself or use a third party lib to do that, for example.

正如Chris Markle指出的那样,Apple 确实从 EXIF 中去除了 GPS 数据。但是您可以打开图像的 RAW 数据,然后自己解析数据或使用第三方库来执行此操作,例如.

Here is a sample code:

这是一个示例代码:

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

    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
    [library assetForURL:[info objectForKey:UIImagePickerControllerReferenceURL]
             resultBlock:^(ALAsset *asset) {

                 ALAssetRepresentation *image_representation = [asset defaultRepresentation];
                 NSUInteger size = (NSUInteger)image_representation.size;
                 // create a buffer to hold image data
                 uint8_t *buffer = (Byte*)malloc(size);
                 NSUInteger length = [image_representation getBytes:buffer fromOffset: 0.0  length:size error:nil];

                 if (length != 0)  {

                     // buffer -> NSData object; free buffer afterwards
                     NSData *adata = [[NSData alloc] initWithBytesNoCopy:buffer length:size freeWhenDone:YES];

                     EXFJpeg* jpegScanner = [[EXFJpeg alloc] init];
                     [jpegScanner scanImageData: adata];
                     EXFMetaData* exifData = jpegScanner.exifMetaData;

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

                     self.locationLabel.text = [NSString stringWithFormat:@"Local: %@ - %@",latitudeValue,longitudeValue];
                     self.dateLavel.text = [NSString stringWithFormat:@"Data: %@", datetime];

                 }
                 else {
                     NSLog(@"image_representation buffer length == 0");
                 }
             }
            failureBlock:^(NSError *error) {
                NSLog(@"couldn't get asset: %@", error);
            }
     ];
}

回答by Nur Iman Izam

This is tested on iOS 8 and works for videos so it should work similarly for photos with a few tweaks.

这在 iOS 8 上进行了测试,适用于视频,因此它应该可以通过一些调整对照片进行类似的工作。

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

    NSURL *videoUrl = (NSURL *)[info objectForKey:UIImagePickerControllerMediaURL];
    NSString *moviePath = [videoUrl path];

    if ( UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(moviePath) ) {

        ALAssetsLibrary *assetLibrary = [[ALAssetsLibrary alloc] init];

        [assetLibrary assetForURL:[info objectForKey:UIImagePickerControllerReferenceURL] resultBlock:^(ALAsset *asset) {

            CLLocation *location = [asset valueForProperty:ALAssetPropertyLocation];
            NSLog(@"Location Meta: %@", location);

        } failureBlock:^(NSError *error) {
            NSLog(@"Video Date Error: %@", error);
        }];

    }

}

回答by Andrey Gordeev

Swiftanswer:

迅捷回答:

import AssetsLibrary
import CoreLocation


// MARK: - UIImagePickerControllerDelegate
extension ViewController: UIImagePickerControllerDelegate {
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
        defer {
            dismiss(animated: true, completion: nil)
        }
        guard picker.sourceType == .photoLibrary else {
            return
        }
        guard let url = info[UIImagePickerControllerReferenceURL] as? URL else {
            return
        }

        let library = ALAssetsLibrary()
        library.asset(for: url, resultBlock: { (asset) in
            guard let coordinate = asset?.value(forProperty: ALAssetPropertyLocation) as? CLLocation else {
                return
            }
            print("\(coordinate)")

            // Getting human-readable address.
            let geocoder = CLGeocoder()
            geocoder.reverseGeocodeLocation(coordinate, completionHandler: { (placemarks, error) in
                guard let placemark = placemarks?.first else {
                    return
                }
                print("\(placemark.addressDictionary)")
            })
        }, failureBlock: { (error: Error?) in
            print("Unable to read metadata: \(error)")
        })
    }
}

回答by rekle

In your UIImagePickerController delegate, do the following:

在您的 UIImagePickerController 委托中,执行以下操作:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
  NSDictionary *metadata = [info valueForKey:UIImagePickerControllerMediaMetadata];

  // metadata now contains all the image metadata.  Extract GPS data from here.
}