I'm using the UIImagePickerController
to take a photo and then upload the photo to a WCF Service
. Along with the image, I also need to send to the latitude and longitude of the photo.
How can I get hold of this information from the photo taken?
I've searched online but can't seem to find a good source of info. I've seen about the EXIF
data that is passed through the UIImagePickerControllerMediaMetadata
key as part of the didFinishPickingMediaWithInfo
delegate method. However, when I print out the contents to the log, there's no location information.
Am I missing something, do I need to turn on location services prior to taking the photo? Or is there another way to get the information?
Many thanks.
I've been figuring this out for a couple of days, and finally got a solution. As already suggested, you can use ALAssetsLibrary.
The image picker will give you a dictionary, which contains an url that points to the asset.
The ALAssetsLibrary's assetForURL: resultBlock: failureBlock:
method uses blocks. You can read more about them from example here.
So this is how we handle the info given by the picker:
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info
{
if ([picker sourceType] == UIImagePickerControllerSourceTypePhotoLibrary) {
// We'll store the info to use in another function later
self.imageInfo = info;
// Get the asset url
NSURL *url = [info objectForKey:@"UIImagePickerControllerReferenceURL"];
// We need to use blocks. This block will handle the ALAsset that's returned:
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset)
{
// Get the location property from the asset
CLLocation *location = [myasset valueForProperty:ALAssetPropertyLocation];
// I found that the easiest way is to send the location to another method
[self handleImageLocation:location];
};
// This block will handle errors:
ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *myerror)
{
NSLog(@"Can not get asset - %@",[myerror localizedDescription]);
// Do something to handle the error
};
// Use the url to get the asset from ALAssetsLibrary,
// the blocks that we just created will handle results
ALAssetsLibrary* assetslibrary = [[[ALAssetsLibrary alloc] init] autorelease];
[assetslibrary assetForURL:url
resultBlock:resultblock
failureBlock:failureblock];
}
[picker dismissModalViewControllerAnimated:YES];
[picker release];
}
And next the method that handles the image and location data:
- handleImageLocation:(CLLocation *)location
{
UIImage *image = [self.imageInfo objectForKey:UIImagePickerControllerOriginalImage];
// Do something with the image and location data...
}
And of course you can also get other information about the image with this method by using keys:
ALAssetPropertyType
ALAssetPropertyLocation
ALAssetPropertyDuration
ALAssetPropertyOrientation
ALAssetPropertyDate
ALAssetPropertyRepresentations
ALAssetPropertyURLs
New since iOS 8
It was complicated with ALAssetLibrary, which is now deprecated, use Photos.Framework instead.
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
if let assertURL = info[UIImagePickerControllerReferenceURL] as? NSURL {
let fetchResult = PHAsset.fetchAssetsWithALAssetURLs([assertURL], options: nil)
if let asset = fetchResult.firstObject as? PHAsset
{
print(asset.location)
}
}
}
Quick and easy :)
It's a 'bug', I guess. A UIImagePickerViewController
won't return location data of the images you select from it: as you've discovered, they are stripped from the meta data.
However, if you use ALAssetLibrary
to get your images you can get the location data (in the form of a CLLocation
object associated with the image). There is some code in this question - iphone image ALAsset problem - that will help you get an ALAsset
from a UIImagePickerController
.
Of course, this would be easier if you could just get that information from the picker straight away, so consider filing a feature request with Apple.
As your source type would appear to be UIImagePickerControllerSourceTypeCamera
, this gets very frustrating very quickly, as you already know. Location info appears to be MIA.
As an alternative to UIImageWriteToSavedPhotosAlbum()
(which does not refer to the saved image) I've tried ALAssetsLibrary and -writeImageToSavedPhotosAlbum:metadata:completionBlock:
(using UIImagePickerControllerMediaMetadata
to populate it, hoping the framework would fill in the blanks with location info).
Alas, no such luck. Even though this method gives back a URL to the saved image, I still can't get ALAssetPropertyLocation
info from it. Even if I use the orientation variant of the save method, it is of no use.
At this point, I think the only recourse would appear to be incorporating your own location info, as outlined here.
It seems somewhat fishy that I'd have to do this, however, as I would expect the framework to handle this for you automagically. In fact, I can't even get location info for previously taken photos. This is with all permissions granted in all the right places, no matter which device I use, iPhone or iPad. (Even the Camera app has proper permission, FWIW.)