我研究了如何从UIImagePickerController
相机返回的图像中获取位置数据。但是,我认为最简单的方法是在CLLocationManager
时刻UIImagePickerController
获取当前位置以捕获图像。
有没有办法做到这一点?有没有办法监听“capturePhoto”事件,例如?
为了澄清一下,使用我的应用程序的用户可能会移动得非常快。
答案 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方法时获取位置。这可能会达到最佳效果。