Cristian
Cristian

Reputation: 238

Extract GPS data from photo

I have a hard time because I want to extract the GPS coordinates from a photo. I use the function imagePickerController:didFinishPickingMediaWithInfo to pick an image and the I am inserting that image in a collectionView using the new Photos framework. I want to extract the GPS coordinates from the photo. I have done some research and I am aware of the fact that UIImage does not contain all the metadata, so I tried using the AssetsLibrary framework. Inside didFinishPickingMediaWithInfo I am using the following code to extract the photo location:

    var referenceURL : NSURL = info.objectForKey(UIImagePickerControllerReferenceURL) as NSURL
    var library : ALAssetsLibrary = ALAssetsLibrary()
    library.assetForURL(referenceURL, resultBlock: { (asset : ALAsset!) -> Void in
        var rep : ALAssetRepresentation = asset.defaultRepresentation()
        var metadata : NSDictionary = rep.metadata()


        let location: AnyObject! = asset.valueForProperty(ALAssetPropertyLocation)
        if location != nil {
            println(location)
        }
        else
        {
            println("Location not found")
        }


         })
    {
            (error : NSError!) -> Void in
    }

However, it doesn't find the location, even though I checked the image and it contains EXIF metadata (it contains also GPS locations, in which I am interested in). How can I retrieve the coordinates from photo?

Upvotes: 13

Views: 13257

Answers (5)

iCoder86
iCoder86

Reputation: 1895

iOS 12 & 13

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

    // For Location
    if let asset = info[UIImagePickerController.InfoKey.phAsset] as? PHAsset {
        print("============> \(asset.location?.coordinate.longitude ?? 0) \(asset.location?.coordinate.latitude ?? 0)")
    }
}

Upvotes: 1

jfgrang
jfgrang

Reputation: 1178

With iOS 11 everything becomes much easier to recover GPS coordinate from a picture in your photo roll.

First import the Photo SDK

import Photos

Then before pushing the UIImagePickerController, ask the authorisation to access the data :

if PHPhotoLibrary.authorizationStatus() == .notDetermined {
    PHPhotoLibrary.requestAuthorization { [weak self](_) in
        // Present the UIImagePickerController
        self?.present(picker, animated: true, completion: nil)
    }
}

Then when you grab back the image from the UIImagePickerController, you only need to do the following to grab the coordinates :

let coordinate = (info[UIImagePickerControllerPHAsset] as? PHAsset)?.location?.coordinate

Upvotes: 3

LNI
LNI

Reputation: 3181

ALAssetsLibrary is deprecated in iOS 10. Fortunately, with Photos framework, this is trivial to implement. When imagePickerController(_ picker:, didFinishPickingMediaWithInfo) is called, you can retrieve location information through a simple lookup. Take a look at the code below:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
   if let URL = info[UIImagePickerControllerReferenceURL] as? URL {
       let opts = PHFetchOptions()
       opts.fetchLimit = 1
       let assets = PHAsset.fetchAssets(withALAssetURLs: [URL], options: opts)
       let asset = assets[0]
       // The location is "asset.location", as a CLLocation 

// ... Other stuff like dismiss omitted
}

Hope this helps. This is Swift 3, of course..

Upvotes: 10

TimWhiting
TimWhiting

Reputation: 2497

func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {

    if picker.sourceType == UIImagePickerControllerSourceType.PhotoLibrary {

        let image = info[UIImagePickerControllerOriginalImage] as! UIImage
        pickedImage.image = image

        let url = info[UIImagePickerControllerReferenceURL] as! NSURL
        let library = ALAssetsLibrary()          
        library.assetForURL(url, resultBlock: { (asset) in
            if let location = asset.valueForProperty(ALAssetPropertyLocation) as? CLLocation {

                self.latitude = location.coordinate.latitude
                self.longitude = location.coordinate.longitude
            }
            }, failureBlock: { (error: NSError!) in
                print("Error!")
        })
    }

    self.dismissViewControllerAnimated(true, completion: nil)
}

Finally managed to get this after trying a lot of different ways, it's remarkably poorly referenced in the apple documentation (or I just couldn't find it). Unfortunately any images that weren't taken through the stock "camera" app don't tend to have location metadata. But it works fine when they do.

Got the answer from https://stackoverflow.com/a/27556241/4337311

Upvotes: 4

Cristian
Cristian

Reputation: 238

I found a solution using the following code:

 if picker.sourceType == UIImagePickerControllerSourceType.PhotoLibrary
    {
        if let currentLat = pickedLat as CLLocationDegrees?
        {
            self.latitude = pickedLat!
            self.longitude = pickedLong!
        }
        else
        {
        var library = ALAssetsLibrary()
        library.enumerateGroupsWithTypes(ALAssetsGroupAll, usingBlock: { (group, stop) -> Void in
                if (group != nil) {

                println("Group is not nil")
                println(group.valueForProperty(ALAssetsGroupPropertyName))
                group.enumerateAssetsUsingBlock { (asset, index, stop) in
                    if asset != nil
                    {
                    if let location: CLLocation = asset.valueForProperty(ALAssetPropertyLocation) as CLLocation!
                    { let lat = location.coordinate.latitude
                        let long = location.coordinate.longitude

                        self.latitude = lat
                        self.longitude = lat

                        println(lat)
                        println(long)
                        }
                    }
                }
            } else
                {
                println("The group is empty!")
                }
            })
            { (error) -> Void in
                println("problem loading albums: \(error)")
        }
    }
}

What it does is that it reads the entire album and prints the location if the photo has that property, else it prints "location not found". It does so for every photo in the album.So I have another question... I want to display the location info just for the photo that I have selected, not for the entire album. Does anyone have a clue how this can be accomplished?

Upvotes: 6

Related Questions