如何在UIImagePickerController瞬间获取当前位置捕获图像?

时间:2014-12-10 00:42:09

标签: ios objective-c image swift geolocation

我研究了如何从UIImagePickerController相机返回的图像中获取位置数据。但是,我认为最简单的方法是在CLLocationManager时刻UIImagePickerController获取当前位置以捕获图像。

有没有办法做到这一点?有没有办法监听“capturePhoto”事件,例如?

为了澄清一下,使用我的应用程序的用户可能会移动得非常快。

3 个答案:

答案 0 :(得分:1)

这是我推荐的内容,因此您不必跟踪用户的位置,因此您可以获得最接近图像实际拍摄时间的用户位置。

CLLocationManager中实例化viewDidLoad类变量,例如:

self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;

确保获得授权:

if ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorizedWhenInUse) {
    [self.locationManager requestWhenInUseAuthorization];
}

(还包括.plist中的“NSLocationWhenInUseUsageDescription”键)

然后你可以等到UIImagePickerController实际出现之前(1)初始化字典以保存位置和(2)开始更新位置,例如:

[self presentViewController:self.imagePicker animated:YES completion:nil];
self.locationDictionary = [[NSMutableDictionary alloc] init];
[self.locationManager startUpdatingLocation];

此时,当NSMutableDictionary委托方法返回self.locationDictionary值时,您可以开始将用户的更新位置存储在CLLocation didUpdateToLocation类实例变量中:

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {

    // Format the current date time to match the format of
    // the photo's metadata timestamp string
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:@"YYYY:MM:dd HH:mm:ss"];
    NSString *stringFromDate = [formatter stringFromDate:[NSDate date]];

    // Add the location as a value in the location NSMutableDictionary
    // while using the formatted current datetime as its key
    [self.locationDictionary setValue:newLocation forKey:stringFromDate];
}

然后一旦选择了图像,在元数据中找到它的时间戳,并在位置字典中找到最接近图像时间戳的时间戳键的值,例如:

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

    [self.locationManager stopUpdatingLocation];

    // When a photo is selected save it as a UIImage
    self.selectedPhoto = info[UIImagePickerControllerOriginalImage];

    // Get the timestamp from the metadata and store it as an NSString
    self.selectedPhotoDateTime = [[[info valueForKey:UIImagePickerControllerMediaMetadata] objectForKey:@"{Exif}"] objectForKey:@"DateTimeOriginal"];

    // If the CLLocationManager is in fact authorized
    // and locations have been found...
    if (self.locationDictionary.allKeys.count > 0) {

        // Sort the location dictionary timestamps in ascending order
        NSArray *sortedKeys = [[self.locationDictionary allKeys] sortedArrayUsingSelector: @selector(compare:)];

        // As a default, set the selected photo's CLLocation class
        // variable to contain the first value in the sorted dictionary
        self.selectedPhotoLocation = [self.locationDictionary objectForKey:[sortedKeys objectAtIndex:0]];

        // Then go through the location dictionary and set the
        // photo location to whatever value in the dictionary
        // has a key containing a time most closely before
        // the image timestamp. Note that the keys can be compared
        // as strings since they're formatted in descending order --
        // year to month to day to hour to minute to second.
        for (NSString *key in sortedKeys) {

            // If the photo's metadata timestamp is less than or equal to
            // the current key, set the selected photo's location class
            // variable to contain the CLLocation value associated with the key
            if ([self.selectedPhotoDateTime compare:key] != NSOrderedAscending) {
                self.selectedPhotoLocation = [self.locationDictionary objectForKey:key];
            }

            // Else if the time in the location dictionary is past
            // the photo's timestamp, break from the loop
            else {
                break;
            }
        }
    }

    [self dismissViewControllerAnimated:YES completion:nil];

}

答案 1 :(得分:0)

.h file中,您需要在代码中添加以下内容:

@interface TakePhotoViewController : UIViewController <CLLocationManagerDelegate>

.m file中,您需要以下内容。

@interface TakePhotoViewController (){
    //location stuff
    CLLocationManager * manager;
    CLGeocoder *geocoder;
    CLPlacemark * placemark;

}

以上代码设置了相关参考资料以找到您的位置。

接下来将此添加到您的viewDidLoad方法:

manager = [[CLLocationManager alloc] init];
geocoder = [[CLGeocoder alloc] init];

这会初始化位置管理器和地理编码器。

然后在您的代码中,要么启动拍照或将图片返回到视图,请使用:

manager.delegate = self;
manager.desiredAccuracy = kCLLocationAccuracyBest;
[manager startUpdatingLocation];

要停止持续更新位置,请将此添加到imagePickerReturn方法:

[manager stopUpdatingLocation];

只要停止更新位置,您就会保存最后更新的位置。该位置每0.5到1秒更新一次,因此即使您正在移动或长时间打开相机,它也只会存储您选择的任何图像的位置。要保存日期(包括时间)减去毫秒)使用:

NSDate * yourCoreDataDateName = [NSDate date];

要获得良好的编码练习以处理任何错误,您需要:

//handles the error if location unavailable
- (void) locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{

    NSLog(@"Error: %@", error);
    NSLog(@"Failed to get location... :-(");

}

- (void) locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{

    NSLog(@"Location: %@", newLocation);
    CLLocation * currentLocation = newLocation;

    self.locationTF.text = @"Finding Location...";

    if (currentLocation != nil){


        [geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
        if (error == nil && [placemarks count] > 0){

            placemark = [placemarks lastObject];
            //the code below translates the coordinates into readable text of the location
            self.locationLabel.text = [NSString stringWithFormat:@"%@ %@ , %@, %@, %@ %@", placemark.subThoroughfare, placemark.thoroughfare, placemark.locality, placemark.administrativeArea, placemark.country, placemark.postalCode];

        }

        else{
            NSLog(@"%@", error.debugDescription);
            self.locationLabel.text = @"Failed to find location";
        }
    }];
    }

}

我必须警告你,当iOS8找不到位置时会抛出 NO 错误,因为它需要你作为程序员来添加警报视图以授权获取位置。请参阅本教程,了解如何克服此问题:

http://nevan.net/2014/09/core-location-manager-changes-in-ios-8/

我从最受欢迎的有关新错误的问题中获得了本教程。

答案 2 :(得分:0)

最准确的方法是通过exif元数据。请看看Ole Begemann关于如何做到这一点的this帖子。

<强>更新

似乎Apple没有将元数据的位置包含在UIImagePicker中使用相机拍摄的图像中。

获取图像拍摄位置的另一个选项是使用UIImagePicker的自定义叠加视图,并在调用takePicture方法时获取位置。这可能会达到最佳效果。